Skip to content

FileClose

Description

Close a file we opened via FileOpen. Idempotent and safe on a borrowed (owns == false) handle; in that case it just clears the local state without touching the underlying fd / HANDLE.

Success

Returns true.

Failure

Returns false if the close syscall failed (logged).

Usage example (Cross-references)

Usage examples (Cross-references)
    #endif
        bool at_eof;  // last read returned 0 bytes
        bool owns;    // true when FileClose should release the handle
    } File;
    }
    
    bool FileClose(File *f) {
        if (!f) {
            return false;
            }
        }
        FileClose(&f);
        return ok;
    }
            return false;
        }
        FileClose(&f);
        return true;
    }
        }
        bool ok = proc_maps_read_all(&f, &out->raw);
        FileClose(&f);
        if (!ok) {
            LOG_ERROR("ProcMapsLoad: FileRead failed");
        i64  written = FileWrite(&f, text, (u64)n);
        bool ok      = (written == (i64)n);
        FileClose(&f);
        if (!ok) {
            FileRemove(out_path);
        Str body = StrInit(alloc_base);
        i64 got  = FileRead(&f, &body);
        FileClose(&f);
    
        bool result = (got == (i64)ZstrLen("hello from file")) && (StrLen(&body) == (size)ZstrLen("hello from file")) &&
        Str body = StrInit(alloc_base);
        i64 got  = FileRead(&f, &body);
        FileClose(&f);
    
        Zstr expected = "this is longer than the initial buffer";
        File f = FileOpen(&path, "rb");
        ok     = ok && FileIsOpen(&f);
        FileClose(&f);
    
        // After close the handle must read as not-open.
        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);
    
        FileRemove(&path);
        ok = ok && (FileSeek(&f, 0, FILE_SEEK_END) == 8);
    
        FileClose(&f);
        FileRemove(&path);
        StrDeinit(&path);
        ok = ok && (FileRead(&f, scratch, 2) == 0) && FileIsEof(&f);
    
        FileClose(&f);
        FileRemove(&path);
        StrDeinit(&path);
        ok     = ok && FileIsOpen(&w);
        ok     = ok && (FileWrite(&w, "new", 3) == 3);
        FileClose(&w);
    
        File r   = FileOpen(&path, "rb");
        Str body = StrInit(alloc_base);
        i64 got  = FileRead(&r, &body);
        FileClose(&r);
    
        ok = ok && (got == 3) && (StrLen(&body) == 3) && ZstrCompare(StrBegin(&body), "new") == 0;
        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);
        FileClose(&r);
    
        ok = ok && (got == 8) && ZstrCompare(StrBegin(&body), "headtail") == 0;
            return false;
        }
        FileClose(&seed);
    
        Zstr payload = "round-trip payload";
            return false;
        }
        FileClose(&seed);
        FileRemove(&path);
        // A read-only handle must reject writes.
        ok = ok && (FileWrite(&f, "X", 1) == -1);
        FileClose(&f);
    
        FileRemove(&path);
        // "r+" must permit writes (does not truncate). Overwrite first 3 bytes.
        ok = ok && (FileWrite(&f, "AAA", 3) == 3);
        FileClose(&f);
    
        // Confirm the write landed.
        File r    = FileOpen(&path, "rb");
        i64  got  = FileRead(&r, &body);
        FileClose(&r);
        ok = ok && (got == 10) && ZstrCompare(StrBegin(&body), "AAA3456789") == 0;
        ok = ok && (got == 7) && (MemCompare(buf, "read-me", 7) == 0);
        ok = ok && (FileWrite(&f, "X", 1) == -1);
        FileClose(&f);
    
        FileRemove(&path);
        // really close the fd and the subsequent owner write would fail.
        File borrowed = FileFromFd(FileFd(&owner));
        FileClose(&borrowed);
    
        // Owner's fd must still be live.
        // Owner's fd must still be live.
        ok = ok && (FileWrite(&owner, "world", 5) == 5);
        FileClose(&owner);
    
        Str body = StrInit(alloc_base);
    // eq_to_ne on `r == 0` would report failure on a clean close.
    bool test_fm_222_close_returns_true(void) {
        WriteFmt("Testing FileClose returns true on a clean close (r == 0)\n");
    
        DefaultAllocator alloc      = DefaultAllocatorInit();
        }
        // A clean close of an owned fd returns true.
        bool ok = (FileClose(&f) == true);
        // And the handle is now not-open.
        ok = ok && !FileIsOpen(&f);
    // would attempt to close fd -1 and could report failure.
    bool test_fm_228_double_close_clears_owns(void) {
        WriteFmt("Testing FileClose clears owns: second close is a no-op true\n");
    
        DefaultAllocator alloc      = DefaultAllocatorInit();
            return false;
        }
        bool ok = FileClose(&f);
        // Second close: fd was reset to -1 and owns to false, so it short-circuits
        // and returns true without touching any fd.
        // Second close: fd was reset to -1 and owns to false, so it short-circuits
        // and returns true without touching any fd.
        ok = ok && (FileClose(&f) == true);
        ok = ok && !FileIsOpen(&f);
        i64 got = FileRead(&f, buf, 5);
        ok      = ok && (got == 5) && (MemCompare(buf, "ABCDE", 5) == 0);
        FileClose(&f);
    
        FileRemove(&path);
        // The next read hits EOF: 0 bytes and at_eof becomes true.
        ok = ok && (FileRead(&f, buf, 2) == 0) && FileIsEof(&f);
        FileClose(&f);
    
        FileRemove(&path);
        char buf2[3] = {0};
        ok           = ok && (FileRead(&f, buf2, 3) == 3) && (MemCompare(buf2, "abc", 3) == 0);
        FileClose(&f);
    
        FileRemove(&path);
        char buf[2] = {0};
        ok          = ok && (FileRead(&f, buf, 1) == 1) && (buf[0] == '7');
        FileClose(&f);
    
        FileRemove(&path);
        Str body = StrInit(alloc_base);
        i64 got  = FileRead(&f, &body);
        FileClose(&f);
    
        ok = ok && (got == 6) && (StrLen(&body) == 6) && ZstrCompare(StrBegin(&body), "ABCDEF") == 0;
        Str body = StrInit(alloc_base);
        i64 got  = FileRead(&f, &body);
        FileClose(&f);
    
        ok = ok && (got == (i64)ZstrLen(payload)) && (StrLen(&body) == (size)ZstrLen(payload)) &&
        }
        ok = ok && (FileWrite(&f, BufData(&src), (u64)N) == (i64)N);
        FileClose(&f);
    
        File r  = FileOpen(&path, "rb");
        Buf dst = BufInit(alloc_base);
        i64 got = FileRead(&r, &dst);
        FileClose(&r);
    
        ok = ok && (got == (i64)N) && (BufLength(&dst) == (size)N) && (MemCompare(BufData(&dst), BufData(&src), N) == 0);
            return false;
        }
        FileClose(&seed);
    
        Zstr payload = "payload-through-the-convenience-API";
            return false;
        }
        FileClose(&seed);
    
        Buf  in = BufInit(alloc_base);
            return false;
        }
        FileClose(&seed);
    
        Str in = StrInit(alloc_base);
        char buf[10] = {0};
        ok           = ok && (FileRead(&f, buf, 9) == 9) && (MemCompare(buf, "temp-data", 9) == 0);
        FileClose(&f);
    
        FileRemove(&path);
        ok = ok && (FileWrite(&f1, "one", 3) == 3);
        ok = ok && (FileWrite(&f2, "twotwo", 6) == 6);
        FileClose(&f1);
        FileClose(&f2);
        ok = ok && (FileWrite(&f2, "twotwo", 6) == 6);
        FileClose(&f1);
        FileClose(&f2);
    
        Str b1 = StrInit(alloc_base);
        // Open handle flushes true.
        bool ok = (FileFlush(&f) == true);
        FileClose(&f);
        // Closed handle must flush false (the open gate fires).
        ok = ok && (FileFlush(&f) == false);
        File seed = FileOpenTemp(&path, alloc_base);
        if (FileIsOpen(&seed)) {
            FileClose(&seed);
        }
    // ---------------------------------------------------------------------------
    bool test_close_releases_fd_slot(void) {
        WriteFmt("Testing FileClose actually releases the fd (slot is reused)\n");
    
        DefaultAllocator alloc      = DefaultAllocatorInit();
        if (!FileIsOpen(&a) || !FileIsOpen(&b)) {
            if (FileIsOpen(&a)) {
                FileClose(&a);
                FileRemove(&pa);
                StrDeinit(&pa);
            }
            if (FileIsOpen(&b)) {
                FileClose(&b);
                FileRemove(&pb);
                StrDeinit(&pb);
        // Really close A. On clean source this frees fd_a; the ge_to_lt mutant
        // skips close() so the kernel still holds fd_a open.
        bool ok = FileClose(&a);
    
        // Reopen a fresh temp. POSIX returns the lowest free fd: on clean source
        bool reuse = (fd_c == fd_a);
    
        FileClose(&b);
        FileClose(&c);
        FileRemove(&pa);
    
        FileClose(&b);
        FileClose(&c);
        FileRemove(&pa);
        FileRemove(&pb);
        FileSeek(&tmp, 0, FILE_SEEK_SET);
        FileRead(&tmp, out);
        FileClose(&tmp);
    }
        FileSeek(&tmp, 0, FILE_SEEK_SET);
        FileRead(&tmp, out);
        FileClose(&tmp);
        return ok;
    }
        FileSeek(&tmp, 0, FILE_SEEK_SET);
        FileRead(&tmp, out);
        FileClose(&tmp);
        return rc;
    }
    
    static void m4_cleanup(File *f, Str *path) {
        FileClose(f);
        FileRemove(path);
        StrDeinit(path);
            ok = (ZstrCompare(StrBegin(&back), expect) == 0);
            StrDeinit(&back);
            FileClose(&f);
        }
        DefaultAllocatorDeinit(&alloc);
        Zstr s   = "World";
        bool ret = FWriteFmt(&f, "Hello {}!", s);
        FileClose(&f);
    
        // Real: write succeeds -> ret true, file holds the exact rendered line.
        i32  n   = 12345;
        bool ret = FWriteFmt(&f, "n={}", n);
        FileClose(&f);
    
        return ret && roundtrip_eq(path, "n=12345");
    
        bool ret = FWriteFmtLn(&f, "line");
        FileClose(&f);
    
        return ret && roundtrip_eq(path, "line\n");
        if (ok) {
            ok = ok && FWriteFmtLn(&f, "n={}", LVAL((i32)42));
            FileClose(&f);
            File r = FileOpen(StrBegin(&path), "r");
            if (FileIsOpen(&r)) {
                ok = ok && (ZstrCompare(StrBegin(&back), "n=42\n") == 0);
                StrDeinit(&back);
                FileClose(&r);
            } else {
                ok = false;
            ok = ok && FWriteFmt(&f, "");
            ok = ok && FWriteFmt(&f, "X");
            FileClose(&f);
            File r = FileOpen(StrBegin(&path), "r");
            if (FileIsOpen(&r)) {
                ok = ok && (ZstrCompare(StrBegin(&back), "X") == 0);
                StrDeinit(&back);
                FileClose(&r);
            } else {
                ok = false;
    
    static void m4_cleanup(File *f, Str *path) {
        FileClose(f);
        FileRemove(path);
        StrDeinit(path);
            FReadFmt(&f, "{}", v);
            ok = (v == 42);
            FileClose(&f);
            FileRemove(&path);
        }
            i64  got = FileRead(&f, &c, 1);
            ok       = (v == 123) && (got == 1) && (c == 'x');
            FileClose(&f);
            FileRemove(&path);
        }
            return false;
        bool ok = (u64)FileWrite(&f, data, size) == size;
        FileClose(&f);
        return ok;
    }
                FileWrite(&f, body, n);
            }
            FileClose(&f);
        }
        return path;
            return false;
        bool ok = FileWrite(&f, data, size) == (i64)size;
        FileClose(&f);
        return ok;
    }
            return false;
        bool ok = FileWrite(&f, data, size) == (i64)size;
        FileClose(&f);
        return ok;
    }
            return false;
        bool ok = FileWrite(&f, data, size) == (i64)size;
        FileClose(&f);
        return ok;
    }
            return false;
        }
        FileClose(&f);
        if (FileWriteAndClose((Zstr)StrBegin(&path), blob, sizeof(blob)) < 0) {
            FileRemove(&path);
            return false;
        }
        FileClose(&f);
        if (FileWriteAndClose((Zstr)StrBegin(&path), junk, sizeof(junk)) < 0) {
            FileRemove(&path);
            wrote_ok = (w == (i64)ZstrLen(late));
        }
        FileClose(&f);
        if (!wrote_ok) {
            FileRemove(&path);
        ProcMaps m;
        bool     loaded = ProcMapsLoadFrom(&m, &rf, &alloc);
        FileClose(&rf);
    
        bool ok = loaded;
        ProcMaps m;
        bool     loaded = ProcMapsLoadFrom(&m, &dir, base);
        FileClose(&dir);
    
        // The unreadable directory makes the chunked read fail, so the loader
        Zstr payload = "hello-body";
        ok           = ok && (FileWrite(&f, payload, ZstrLen(payload)) == (i64)ZstrLen(payload));
        FileClose(&f);
    
        HttpResponse  response = HttpResponseInit(alloc_base);
        File f    = FileOpenTemp(&path, alloc_base);
        bool ok   = FileIsOpen(&f);
        FileClose(&f); // leave it empty
    
        HttpResponse  response = HttpResponseInit(alloc_base);
        Zstr payload = "file-payload-long-enough-to-heap-allocate-body";
        ok           = ok && (FileWrite(&f, payload, ZstrLen(payload)) == (i64)ZstrLen(payload));
        FileClose(&f);
    
        // Serving the file must free the old (HTML) body before installing the new.
            return false;
        }
        FileClose(&seed);
    
        u8 buf[HDR_SIZE + SEG64_HDR];
            return false;
        }
        FileClose(&seed);
    
        // Bad magic (not a Mach-O), but enough bytes to read successfully.
Last updated on