Skip to content

File

Description

Cross-platform file handle. Linux uses an fd through direct syscalls, macOS uses an fd through libSystem, Windows uses a HANDLE. The API surface (FileOpen / Close / Read / Write / Seek / Tell / Flush / Eof) is identical across platforms.

Value type – caller stack-allocates and passes by pointer. A failed open leaves fd (or handle) negative / INVALID; check with FileIsOpen after open.

Usage example (Cross-references)

Usage examples (Cross-references)
    
    #if FEATURE_FILE
    #    include <Misra/Std/File.h>
    #endif
    #include <Misra/Std/Container/Str.h>
    #include <Misra/Std/Container/Vec.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Zstr.h>
    #include <Misra/Types.h>
            Zstr       about;
            ArgSpecs   specs;
            File      *out;
        } ArgParse;
        bool at_eof;  // last read returned 0 bytes
        bool owns;    // true when FileClose should release the handle
    } File;
    
    ///
    /// TAGS: File, Open, API
    ///
    File file_open(Zstr path, Zstr mode);
    #define FileOpen(path, mode)                                                                                           \
        _Generic(                                                                                                          \
    /// TAGS: File, FromFd, Wrap, FileDescriptor
    ///
    File FileFromFd(i32 fd);
    
    ///
    /// TAGS: File, Stdio, API
    ///
    File FileStdin(void);
    File FileStdout(void);
    File FileStderr(void);
    ///
    File FileStdin(void);
    File FileStdout(void);
    File FileStderr(void);
    File FileStdin(void);
    File FileStdout(void);
    File FileStderr(void);
    
    ///
    /// TAGS: File, Close, API
    ///
    bool FileClose(File *f);
    
    ///
    /// TAGS: File, Query, State, Open
    ///
    bool FileIsOpen(const File *f);
    
    ///
    /// TAGS: File, Read
    ///
    i64 file_read(File *f, void *buf, u64 n);
    i64 file_read_to_str(File *f, Str *out);
    i64 file_read_to_buf(File *f, Buf *out);
    ///
    i64 file_read(File *f, void *buf, u64 n);
    i64 file_read_to_str(File *f, Str *out);
    i64 file_read_to_buf(File *f, Buf *out);
    #define FileRead(...) OVERLOAD(FileRead, __VA_ARGS__)
    i64 file_read(File *f, void *buf, u64 n);
    i64 file_read_to_str(File *f, Str *out);
    i64 file_read_to_buf(File *f, Buf *out);
    #define FileRead(...) OVERLOAD(FileRead, __VA_ARGS__)
    #define FileRead_2(f, out)                                                                                             \
    /// TAGS: File, Write, API
    ///
    i64 FileWrite(File *f, const void *buf, u64 n);
    
    ///
    /// TAGS: File, Seek, Position
    ///
    i64 FileSeek(File *f, i64 offset, FileWhence whence);
    
    ///
    /// TAGS: File, Position, Tell
    ///
    i64 FileTell(File *f);
    
    ///
    /// TAGS: File, Flush, API
    ///
    bool FileFlush(File *f);
    
    ///
    /// TAGS: File, EOF, Query
    ///
    bool FileIsEof(const File *f);
    
    ///
    /// TAGS: File, FileDescriptor, API
    ///
    i32 FileFd(const File *f);
    
    ///
    /// TAGS: File, Temp
    ///
    File file_open_temp(Str *out_path, Allocator *alloc);
    #define FileOpenTemp(...)               OVERLOAD(FileOpenTemp, __VA_ARGS__)
    #define FileOpenTemp_1(out_path)        file_open_temp((out_path), MisraScope)
    #include <Misra/Std/DateTime.h>
    #include <Misra/Std/Zstr.h>
    #include <Misra/Std/File.h>
    #include <Misra/Types.h>
    #define WriteFmt(...)                                                                                                  \
        do {                                                                                                               \
            File UNPL(out) = FileStdout();                                                                                 \
            FWriteFmt(&UNPL(out), __VA_ARGS__);                                                                            \
        } while (0)
    #define WriteFmtLn(...)                                                                                                \
        do {                                                                                                               \
            File UNPL(out) = FileStdout();                                                                                 \
            FWriteFmtLn(&UNPL(out), __VA_ARGS__);                                                                          \
        } while (0)
    #define ReadFmt(...)                                                                                                   \
        do {                                                                                                               \
            File UNPL(in) = FileStdin();                                                                                   \
            FReadFmt(&UNPL(in), __VA_ARGS__);                                                                              \
        } while (0)
    #include <Misra/Std/Container/Str.h>
    #include <Misra/Std/Container/Vec.h>
    #include <Misra/Std/File.h>
    #include <Misra/Types.h>
    ///
    bool proc_maps_load_from_bytes(ProcMaps *out, const u8 *bytes, u64 len, Allocator *alloc);
    bool proc_maps_load_from_file(ProcMaps *out, File *f, Allocator *alloc);
    #define ProcMapsLoadFrom(...) OVERLOAD(ProcMapsLoadFrom, __VA_ARGS__)
    #define ProcMapsLoadFrom_2(out, src)                                                                                   \
        _Generic(                                                                                                          \
            (src),                                                                                                         \
            File *: proc_maps_load_from_file((out), (File *)(src), MisraScope),                                            \
            Str *: proc_maps_load_from_bytes((out), (const u8 *)StrBegin((Str *)(src)), StrLen((Str *)(src)), MisraScope), \
            Buf *: proc_maps_load_from_bytes((out), BufData((Buf *)(src)), BufLength((Buf *)(src)), MisraScope)            \
        _Generic(                                                                                                          \
            (src),                                                                                                         \
            File *: proc_maps_load_from_file((out), (File *)(src), ALLOCATOR_OF(alloc)),                                   \
            Str *: proc_maps_load_from_bytes(                                                                              \
                     (out),                                                                                                \
    #ifdef EEXIST
            case EEXIST :
                return "File exists";
    #endif
    #ifdef EXDEV
    #ifdef EFBIG
            case EFBIG :
                return "File too large";
    #endif
    #ifdef ENOSPC
    #ifdef ENAMETOOLONG
            case ENAMETOOLONG :
                return "File name too long";
    #endif
    #ifdef ENOTEMPTY
    #include <Misra/Std/Allocator/Heap.h>
    #include <Misra/Std/Container/Str.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Io.h>
    #include <Misra/Std/Log.h>
        StrAppendFmt(&full, "[{}] [{}:{}] {}\n", (Zstr)NAMES[type], (Zstr)tag, line, (Zstr)msg);
    
        File out = (type == LOG_MESSAGE_TYPE_INFO) ? FileFromFd(1) : FileFromFd(2);
        (void)FileWrite(&out, StrBegin(&full), StrLen(&full));
    #include <Misra/Std/Container/Buf.h>
    #include <Misra/Std/Container/Str.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/Prng.h>
    // ---------------------------------------------------------------------------
    
    File file_open(Zstr path, Zstr mode) {
        File f = {0};
    #if PLATFORM_WINDOWS
    
    File file_open(Zstr path, Zstr mode) {
        File f = {0};
    #if PLATFORM_WINDOWS
        f.handle = INVALID_HANDLE_VALUE;
    }
    
    File FileFromFd(i32 fd) {
        File f = {0};
    #if PLATFORM_WINDOWS
    
    File FileFromFd(i32 fd) {
        File f = {0};
    #if PLATFORM_WINDOWS
        (void)fd;
    }
    
    File FileStdin(void) {
    #if PLATFORM_WINDOWS
        File f = {.handle = GetStdHandle(STD_INPUT_HANDLE), .owns = false};
    File FileStdin(void) {
    #if PLATFORM_WINDOWS
        File f = {.handle = GetStdHandle(STD_INPUT_HANDLE), .owns = false};
        return f;
    #else
    }
    
    File FileStdout(void) {
    #if PLATFORM_WINDOWS
        File f = {.handle = GetStdHandle(STD_OUTPUT_HANDLE), .owns = false};
    File FileStdout(void) {
    #if PLATFORM_WINDOWS
        File f = {.handle = GetStdHandle(STD_OUTPUT_HANDLE), .owns = false};
        return f;
    #else
    }
    
    File FileStderr(void) {
    #if PLATFORM_WINDOWS
        File f = {.handle = GetStdHandle(STD_ERROR_HANDLE), .owns = false};
    File FileStderr(void) {
    #if PLATFORM_WINDOWS
        File f = {.handle = GetStdHandle(STD_ERROR_HANDLE), .owns = false};
        return f;
    #else
    }
    
    bool FileClose(File *f) {
        if (!f) {
            return false;
    }
    
    bool FileIsOpen(const File *f) {
        if (!f) {
            return false;
    // ---------------------------------------------------------------------------
    
    i64 file_read(File *f, void *buf, u64 n) {
        if (!FileIsOpen(f) || !buf) {
            return -1;
    }
    
    i64 FileWrite(File *f, const void *buf, u64 n) {
        if (!FileIsOpen(f) || !buf) {
            return -1;
    }
    
    i64 FileSeek(File *f, i64 offset, FileWhence whence) {
        if (!FileIsOpen(f)) {
            return -1;
    }
    
    i64 FileTell(File *f) {
        return FileSeek(f, 0, FILE_SEEK_CUR);
    }
    }
    
    bool FileFlush(File *f) {
        if (!FileIsOpen(f)) {
            return false;
    }
    
    bool FileIsEof(const File *f) {
        return f && f->at_eof;
    }
    }
    
    i32 FileFd(const File *f) {
    #if PLATFORM_WINDOWS
        (void)f;
    #include <Misra/Std/ArgParse.h>
    #include <Misra/Std/Zstr.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Io.h>
    #include <Misra/Std/Log.h>
    
    static void print_help(ArgParse *self) {
        File err = self->out ? *self->out : FileStderr();
    
        if (self->about) {
        int       argc,
        char    **argv,
        File     *err
    ) {
        bool is_long  = (tok[0] == '-' && tok[1] == '-');
    // when -v is a Flag or a Count. -lFOO (stuck value) is intentionally
    // not supported in v1.
    static ArgRun handle_short_bundle(ArgParse *self, Zstr tok, File *err) {
        // tok looks like "-XYZ..."; verify every char maps to a Flag/Count.
        ArgRun result = ARG_RUN_OK;
        }
    
        File err = self->out ? *self->out : FileStderr();
    
        bool rest_positional = false;
    #include <Misra/Std/Container/Buf.h>
    #include <Misra/Std/Container/Str.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Io.h>
    #include <Misra/Std/Log.h>
    }
    
    bool f_write_fmt(File *stream, Zstr fmtstr, TypeSpecificIO *argv, u64 argc, bool append_newline) {
        Str  out;
        bool ok = true;
    }
    
    void f_read_fmt(File *file, Zstr fmtstr, TypeSpecificIO *argv, u64 argc) {
        // DefaultAllocator: the slurp buffer below sizes itself from file length
        // (potentially many MiB on seekable inputs), so no stack-bound applies.
                return "Unknown";
            case DIR_ENTRY_TYPE_REGULAR_FILE :
                return "Regular File";
            case DIR_ENTRY_TYPE_DIRECTORY :
                return "Directory";
    
    #include <Misra/Std.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/Memory.h>
    #include <Misra/Std/Memory.h>
    
    #include <Misra/Std/File.h>
    
    // ---------------------------------------------------------------------------
    #include <Misra/Std.h>
    #include <Misra/Std/Container/Str.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/Memory.h>
    #include <Misra/Std/Allocator/Arena.h>
    #include <Misra/Std/Allocator/Heap.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/Memory.h>
    // with an empty Str.
    static bool slurp_file(Zstr path, Str *out) {
        File f = FileOpen(path, "rb");
        if (!FileIsOpen(&f)) {
            // Missing config file is fine -- resolver just won't know about it.
    #include <Misra/Std/Container/Str.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Memory.h>
    #define MISRA_SYS_HELPERS_H
    
    #include <Misra/Std/File.h>
    #include <Misra/Std/Container/Str.h>
    #include <Misra/Std/Zstr.h>
    /// callers (cache lookups, sidecar discovery).
    static inline bool sys_path_exists(Zstr path) {
        File f = FileOpen(path, "rb");
        if (!FileIsOpen(&f)) {
            return false;
    #include <Misra/Std.h>
    #include <Misra/Std/Container/Buf.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/Memory.h>
    #include <Misra/Parsers/Pdb.h>
    #include <Misra/Std.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/Math.h>
    
    #include <Misra/Std.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Io.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/Memory.h>
    
    #include <Misra/Std/File.h>
    #include <Misra/Std/Utility/StrIter.h>
    // NOT EOF: treating it as one drops every later entry, including [stack]).
    // Does not close `f`.
    static bool proc_maps_read_all(File *f, Str *raw) {
        enum {
            CHUNK = 4096
        // `/proc/self/maps` reports stat-size 0 because it's generated by the
        // kernel on read, so we loop-read into a growing buffer ourselves.
        File f = FileOpen("/proc/self/maps", "rb");
        if (!FileIsOpen(&f)) {
            LOG_ERROR("ProcMapsLoad: FileOpen(/proc/self/maps) failed");
    }
    
    bool proc_maps_load_from_file(ProcMaps *out, File *f, Allocator *alloc) {
        if (!out || !f || !alloc) {
            LOG_FATAL("ProcMapsLoadFrom: NULL argument");
    
    #if FEATURE_FILE
    #    include <Misra/Std/File.h>
    #endif
    #include <Misra/Parsers/MachO.h>
    #include <Misra/Std.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/Memory.h>
    
    #include <Misra/Std.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Io.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/Allocator/Default.h>
    #include <Misra/Std/Container/Str.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/Memory.h>
    // caller can read it back and remove it.
    static bool write_test_file(Zstr text, Str *out_path, Allocator *alloc) {
        File f = FileOpenTemp(out_path, alloc);
        if (!FileIsOpen(&f)) {
            return false;
        }
    
        File f = FileOpen(&path, "rb");
        if (!FileIsOpen(&f)) {
            FileRemove(&path);
        }
    
        File f = FileOpen(&path, "rb");
        if (!FileIsOpen(&f)) {
            FileRemove(&path);
        }
    
        File f = FileOpen(&path, "rb");
        ok     = ok && FileIsOpen(&f);
        FileClose(&f);
    
        // "q" is not a recognised mode.
        File f = FileOpen(&path, "q");
        ok     = ok && !FileIsOpen(&f);
        FileClose(&f);
    
        // An empty mode is also rejected.
        File g = FileOpen(&path, "");
        ok     = ok && !FileIsOpen(&g);
        FileClose(&g);
    
        Str  path;
        File f = FileOpenTemp(&path, alloc_base);
        if (!FileIsOpen(&f)) {
            DefaultAllocatorDeinit(&alloc);
        }
    
        File f = FileOpen(&path, "rb");
        ok     = ok && FileIsOpen(&f);
        }
    
        File w = FileOpen(&path, "w");
        ok     = ok && FileIsOpen(&w);
        ok     = ok && (FileWrite(&w, "new", 3) == 3);
        FileClose(&w);
    
        File r   = FileOpen(&path, "rb");
        ok       = ok && FileIsOpen(&r);
        Str body = StrInit(alloc_base);
        }
    
        File a = FileOpen(&path, "a");
        ok     = ok && FileIsOpen(&a);
        ok     = ok && (FileWrite(&a, "tail", 4) == 4);
        FileClose(&a);
    
        File r    = FileOpen(&path, "rb");
        Str  body = StrInit(alloc_base);
        i64  got  = FileRead(&r, &body);
        // then write to it through the convenience API.
        Str  path;
        File seed = FileOpenTemp(&path, alloc_base);
        if (!FileIsOpen(&seed)) {
            DefaultAllocatorDeinit(&alloc);
        // Mint a unique name then remove it so the path is guaranteed absent.
        Str  path;
        File seed = FileOpenTemp(&path, alloc_base);
        if (!FileIsOpen(&seed)) {
            DefaultAllocatorDeinit(&alloc);
        }
    
        File f = FileOpen(&path, "r");
        ok     = ok && FileIsOpen(&f);
        // A read-only handle must reject writes.
        }
    
        File f = FileOpen(&path, "r+");
        ok     = ok && FileIsOpen(&f);
        // "r+" must permit writes (does not truncate). Overwrite first 3 bytes.
        // Confirm the write landed.
        Str  body = StrInit(alloc_base);
        File r    = FileOpen(&path, "rb");
        i64  got  = FileRead(&r, &body);
        FileClose(&r);
        }
    
        File f      = FileOpen(&path, "r");
        ok          = ok && FileIsOpen(&f);
        char buf[8] = {0};
    #else
        // fd 1 (stdout) is a stable, known descriptor.
        File f  = FileFromFd(1);
        bool ok = (FileFd(&f) == 1);
        // A different fd surfaces distinctly too.
        bool ok = (FileFd(&f) == 1);
        // A different fd surfaces distinctly too.
        File g = FileFromFd(0);
        ok     = ok && (FileFd(&g) == 0);
        return ok;
    
        Str  path;
        File owner = FileOpenTemp(&path, alloc_base);
        if (!FileIsOpen(&owner)) {
            DefaultAllocatorDeinit(&alloc);
        // the fd is left open; if the mutant set owns=true, this close would
        // really close the fd and the subsequent owner write would fail.
        File borrowed = FileFromFd(FileFd(&owner));
        FileClose(&borrowed);
    
        Str  path;
        File f = FileOpenTemp(&path, alloc_base);
        if (!FileIsOpen(&f)) {
            DefaultAllocatorDeinit(&alloc);
    
        Str  path;
        File f = FileOpenTemp(&path, alloc_base);
        if (!FileIsOpen(&f)) {
            DefaultAllocatorDeinit(&alloc);
    
        Str  path;
        File f = FileOpenTemp(&path, alloc_base);
        if (!FileIsOpen(&f)) {
            DefaultAllocatorDeinit(&alloc);
        }
    
        File f      = FileOpen(&path, "rb");
        ok          = ok && FileIsOpen(&f);
        char buf[4] = {0};
        }
    
        File f      = FileOpen(&path, "rb");
        ok          = ok && FileIsOpen(&f);
        char buf[8] = {0};
    
        Str  path;
        File f = FileOpenTemp(&path, alloc_base);
        if (!FileIsOpen(&f)) {
            DefaultAllocatorDeinit(&alloc);
        }
    
        File f = FileOpen(&path, "rb");
        ok     = ok && FileIsOpen(&f);
        // Move the cursor to offset 10; remaining size must be 16 - 10 = 6.
        }
    
        File f   = FileOpen(&path, "rb");
        ok       = ok && FileIsOpen(&f);
        Str body = StrInit(alloc_base);
        // Build a 10000-byte payload (> FILE_READ_CHUNK=4096) on disk.
        Str  path;
        File f = FileOpenTemp(&path, alloc_base);
        if (!FileIsOpen(&f)) {
            DefaultAllocatorDeinit(&alloc);
        FileClose(&f);
    
        File r  = FileOpen(&path, "rb");
        ok      = ok && FileIsOpen(&r);
        Buf dst = BufInit(alloc_base);
    
        Str  path;
        File seed = FileOpenTemp(&path, alloc_base);
        if (!FileIsOpen(&seed)) {
            DefaultAllocatorDeinit(&alloc);
    
        Str  path;
        File seed = FileOpenTemp(&path, alloc_base);
        if (!FileIsOpen(&seed)) {
            DefaultAllocatorDeinit(&alloc);
    
        Str  path;
        File seed = FileOpenTemp(&path, alloc_base);
        if (!FileIsOpen(&seed)) {
            DefaultAllocatorDeinit(&alloc);
    
        Str  path;
        File f  = FileOpenTemp(&path, alloc_base);
        bool ok = FileIsOpen(&f);
        // The resolved path must be non-empty (16 hex chars).
    
        Str  p1;
        File f1 = FileOpenTemp(&p1, alloc_base);
        Str  p2;
        File f2 = FileOpenTemp(&p2, alloc_base);
        File f1 = FileOpenTemp(&p1, alloc_base);
        Str  p2;
        File f2 = FileOpenTemp(&p2, alloc_base);
    
        bool ok = FileIsOpen(&f1) && FileIsOpen(&f2);
    
        Str  path;
        File f = FileOpenTemp(&path, alloc_base);
        if (!FileIsOpen(&f)) {
            DefaultAllocatorDeinit(&alloc);
    
        Str  path;
        File seed = FileOpenTemp(&path, alloc_base);
        if (FileIsOpen(&seed)) {
            FileClose(&seed);
        // fd 0 (stdin) is a valid, open descriptor. `>= 0` must accept it;
        // a `> 0` mutant would wrongly report it not-open.
        File f  = FileFromFd(0);
        bool ok = (FileIsOpen(&f) == true);
        // Sanity: a genuinely-negative fd is not open under either form, so
        // Sanity: a genuinely-negative fd is not open under either form, so
        // the discriminating case really is fd == 0.
        File g = FileFromFd(-1);
        ok     = ok && (FileIsOpen(&g) == false);
        return ok;
        // middle of the table. Record A's fd.
        Str  pa;
        File a = FileOpenTemp(&pa, alloc_base);
        Str  pb;
        File b = FileOpenTemp(&pb, alloc_base);
        File a = FileOpenTemp(&pa, alloc_base);
        Str  pb;
        File b = FileOpenTemp(&pb, alloc_base);
        if (!FileIsOpen(&a) || !FileIsOpen(&b)) {
            if (FileIsOpen(&a)) {
        // occupied so we get a strictly higher number.
        Str  pc;
        File c     = FileOpenTemp(&pc, alloc_base);
        ok         = ok && FileIsOpen(&c);
        i32  fd_c  = FileFd(&c);
    
    int main(void) {
        WriteFmt("[INFO] Starting File tests\n\n");
    
        TestFunction tests[] = {
            deadend_tests,
            sizeof(deadend_tests) / sizeof(deadend_tests[0]),
            "File"
        );
    }
    #include <Misra/Std/ArgParse.h>
    #include <Misra/Std/Container/Str.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Io.h>
    #include <Misra/Std/Log.h>
    static void capture_help(ArgParse *p, Str *out) {
        Str  tmp_path = StrInit(p->alloc);
        File tmp      = FileOpenTemp(&tmp_path, p->alloc);
        StrDeinit(&tmp_path);
        if (!FileIsOpen(&tmp))
    static bool capture_help_file(ArgParse *p, Str *out) {
        Str  tmp_path = StrInit(p->alloc);
        File tmp      = FileOpenTemp(&tmp_path, p->alloc);
        StrDeinit(&tmp_path);
        if (!FileIsOpen(&tmp))
    static ArgRun capture_run(ArgParse *p, int argc, char **argv, Str *out) {
        Str  tmp_path = StrInit(p->alloc);
        File tmp      = FileOpenTemp(&tmp_path, p->alloc);
        StrDeinit(&tmp_path);
        if (!FileIsOpen(&tmp))
    #include <Misra/Std/Allocator.h>
    #include <Misra/Std/Container/Buf.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Io/Private.h>
    #include <Misra/Std/Memory.h>
    // File (positioned at 0) and stashing the path in `*out_path` so the
    // caller can FileRemove + StrDeinit it afterwards.
    static File m4_make_temp(DefaultAllocator *alloc, Str *out_path, const char *content, u64 len) {
        File f = FileOpenTemp(out_path, alloc);
        if (!FileIsOpen(&f))
    // caller can FileRemove + StrDeinit it afterwards.
    static File m4_make_temp(DefaultAllocator *alloc, Str *out_path, const char *content, u64 len) {
        File f = FileOpenTemp(out_path, alloc);
        if (!FileIsOpen(&f))
            return f;
    }
    
    static void m4_cleanup(File *f, Str *path) {
        FileClose(f);
        FileRemove(path);
    static bool roundtrip_eq(Zstr path, Zstr expect) {
        DefaultAllocator alloc = DefaultAllocatorInit();
        File             f     = FileOpen(path, "r");
        bool             ok    = false;
        if (FileIsOpen(&f)) {
    static bool test_m28_fwrite_roundtrip_string(void) {
        Zstr path = "io_mutants28_str.txt"; // CWD-relative: portable (no /tmp on Windows)
        File f    = FileOpen(path, "w");
        if (!FileIsOpen(&f)) {
            return false;
    static bool test_m28_fwrite_roundtrip_int(void) {
        Zstr path = "io_mutants28_int.txt"; // CWD-relative: portable (no /tmp on Windows)
        File f    = FileOpen(path, "w");
        if (!FileIsOpen(&f)) {
            return false;
    static bool test_m28_fwriteln_roundtrip(void) {
        Zstr path = "io_mutants28_ln.txt"; // CWD-relative: portable (no /tmp on Windows)
        File f    = FileOpen(path, "w");
        if (!FileIsOpen(&f)) {
            return false;
        DefaultAllocator alloc = DefaultAllocatorInit();
        Str              path  = StrInit(&alloc);
        File             f     = m4_make_temp(&alloc, &path, "42 zzzzzzz", 10);
        bool             ok    = FileIsOpen(&f);
        DefaultAllocator alloc = DefaultAllocatorInit();
        Str              path  = StrInit(&alloc);
        File             f     = m4_make_temp(&alloc, &path, "7", 1);
        bool             ok    = FileIsOpen(&f);
        DefaultAllocator alloc = DefaultAllocatorInit();
        Str              path  = StrInit(&alloc);
        File             f     = m4_make_temp(&alloc, &path, "53 and more text", 16);
        bool             ok    = FileIsOpen(&f);
        DefaultAllocator alloc = DefaultAllocatorInit();
        Str              path  = StrInit(&alloc);
        File             f     = FileOpenTemp(&path, &alloc);
        bool             ok    = FileIsOpen(&f);
        if (ok) {
            ok = ok && FWriteFmtLn(&f, "n={}", LVAL((i32)42));
            FileClose(&f);
            File r = FileOpen(StrBegin(&path), "r");
            if (FileIsOpen(&r)) {
                Str back = StrInit(&alloc);
        DefaultAllocator alloc = DefaultAllocatorInit();
        Str              path  = StrInit(&alloc);
        File             f     = FileOpenTemp(&path, &alloc);
        bool             ok    = FileIsOpen(&f);
        if (ok) {
            ok = ok && FWriteFmt(&f, "X");
            FileClose(&f);
            File r = FileOpen(StrBegin(&path), "r");
            if (FileIsOpen(&r)) {
                Str back = StrInit(&alloc);
    #include <Misra/Std/Io.h>
    #include <Misra/Std/Io/Private.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/Memory.h>
    // File (positioned at 0) and stashing the path in `*out_path` so the
    // caller can FileRemove + StrDeinit it afterwards.
    static File m4_make_temp(DefaultAllocator *alloc, Str *out_path, const char *content, u64 len) {
        File f = FileOpenTemp(out_path, alloc);
        if (!FileIsOpen(&f))
    // caller can FileRemove + StrDeinit it afterwards.
    static File m4_make_temp(DefaultAllocator *alloc, Str *out_path, const char *content, u64 len) {
        File f = FileOpenTemp(out_path, alloc);
        if (!FileIsOpen(&f))
            return f;
    }
    
    static void m4_cleanup(File *f, Str *path) {
        FileClose(f);
        FileRemove(path);
        content[51] = '1';
    
        File f  = m4_make_temp(&alloc, &path, content, 52);
        bool ok = FileIsOpen(&f);
        DefaultAllocator alloc = DefaultAllocatorInit();
        Str              path  = StrInit(&alloc);
        File             f     = m4_make_temp(&alloc, &path, "", 0);
        bool             ok    = FileIsOpen(&f);
        DefaultAllocator alloc = DefaultAllocatorInit();
        Str              path  = StrInit(&alloc);
        File             f     = FileOpenTemp(&path, &alloc);
        bool             ok    = FileIsOpen(&f);
        if (ok) {
        DefaultAllocator alloc = DefaultAllocatorInit();
        Str              path  = StrInit(&alloc);
        File             f     = FileOpenTemp(&path, &alloc);
        bool             ok    = FileIsOpen(&f);
        if (ok) {
        // Use Misra's File API so this test runs under -nostdlib too
        // (no libc fopen/fwrite/fclose).
        File f = FileOpen(path, "w");
        if (!FileIsOpen(&f))
            return false;
    #include <Misra/Std/Allocator/Default.h>
    #include <Misra/Std/Container/Str/Init.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Std/Zstr.h>
    static Str write_temp(Allocator *a, Zstr body) {
        Str  path = StrInit(a);
        File f    = file_open_temp(&path, a);
        if (FileIsOpen(&f)) {
            u64 n = ZstrLen(body);
    #include <Misra/Std/Zstr.h>
    #include <Misra/Std/Memory.h>
    #include <Misra/Std/File.h>
    #include <Misra/Sys.h>
    #include <Misra/Sys/MachoCache.h>
    
    static bool write_file(Zstr path, const u8 *data, u64 size) {
        File f = FileOpen(path, "wb");
        if (!FileIsOpen(&f))
            return false;
    
    static bool mc_write_file(Zstr path, const u8 *data, u64 size) {
        File f = FileOpen(path, "wb");
        if (!FileIsOpen(&f))
            return false;
    
    static bool bl_write_file(Zstr path, const u8 *data, u64 size) {
        File f = FileOpen(path, "wb");
        if (!FileIsOpen(&f))
            return false;
    #include <Misra/Std/Allocator/Default.h>
    #include <Misra/Std/Container/Str.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Memory.h>
    #include <Misra/Sys/Dir.h>
    
        Str  path = StrInit(base);
        File f    = FileOpenTemp(&path, base);
        if (!FileIsOpen(&f)) {
            StrDeinit(&path);
    
        Str  path = StrInit(base);
        File f    = FileOpenTemp(&path, base);
        if (!FileIsOpen(&f)) {
            StrDeinit(&path);
    #include <Misra/Std/Allocator/Debug.h>
    #include <Misra/Std/Container/Buf.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Memory.h>
    #include <Misra/Std/Allocator/Default.h>
    #include <Misra/Std/Container/Str.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Zstr.h>
    #include <Misra/Parsers/ProcMaps.h>
    
        Str  path;
        File f = FileOpenTemp(&path, alloc_base);
        if (!FileIsOpen(&f)) {
            DefaultAllocatorDeinit(&alloc);
        }
    
        File rf = FileOpen(&path, "rb");
        if (!FileIsOpen(&rf)) {
            FileRemove(&path);
    
        // A directory: open(2) succeeds (FileIsOpen true) but read(2) returns -1.
        File dir = FileOpen("/proc/self", "rb");
        if (!FileIsOpen(&dir)) {
            DebugAllocatorDeinit(&dbg);
    #include <Misra.h>
    #include <Misra/Parsers/Http.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Zstr.h>
    #include <Misra/Std/Allocator/Debug.h>
    
        Str  path = StrInit(alloc_base);
        File f    = FileOpenTemp(&path, alloc_base);
        bool ok   = FileIsOpen(&f);
    
        Str  path = StrInit(alloc_base);
        File f    = FileOpenTemp(&path, alloc_base);
        bool ok   = FileIsOpen(&f);
        FileClose(&f); // leave it empty
        // Create a temp file with content.
        Str  path    = StrInit(adbg);
        File f       = FileOpenTemp(&path, adbg);
        bool ok      = FileIsOpen(&f);
        Zstr payload = "file-payload-long-enough-to-heap-allocate-body";
    #include <Misra/Std/Allocator/Default.h>
    #include <Misra/Std/Container/Str.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Memory.h>
    #include <Misra/Std/Zstr.h>
        // Mint a unique temp path, then write a minimal valid Mach-O to it.
        Str  path;
        File seed = FileOpenTemp(&path, base);
        if (!FileIsOpen(&seed)) {
            DefaultAllocatorDeinit(&alloc);
    
        Str  path;
        File seed = FileOpenTemp(&path, base);
        if (!FileIsOpen(&seed)) {
            DefaultAllocatorDeinit(&alloc);
    #include <Misra/Parsers/Elf.h>
    #include <Misra/Std/Allocator/Default.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Memory.h>
    #include <Misra/Parsers/Elf.h>
    #include <Misra/Std/Allocator/Default.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Log.h>
    #include <Misra/Sys/SymbolResolver.h>
Last updated on