Quick sprint after the pthread #PF fix earlier today: flipping fsync, fdatasync, and sync from the partial / no columns to honest yes on both the C++ and Rust kernels. Pattern follows yesterday's POSIX-TRUNCATE landing — pick a small cluster of related libc primitives that are almost there, finish the surface, ship a regression, flip the data file.
Why They Were Partial in the First Place
The kernel side had been correct for a while. JefeOS writes go through a synchronous write_sectors path on NTFS, FAT32, and JefeFS — there is no deferred dirty queue to flush, so sys_fsync just validates the fd and returns 0 (or EBADF for a bad descriptor). What was missing was the libc surface. Programs ported in had no fsync() thunk to call; the scorecard was honestly reflecting that gap.
sys_sync() on the C++ side was already returning 0, but the libc had no sync(void) wrapper either, so it stayed at no. Sysconf was the giveaway: _SC_FSYNC and _SC_SYNCHRONIZED_IO both returned -1 ("not supported"), which was true while the libc didn't expose the calls but became wrong the moment we added them.
The Sprint
- SYS_FDATASYNC = 318 on both kernels (next free native syscall). Collapses to
sys_fsyncinternally — there is no separated metadata-vs-data dirty queue to skip differently. - libc thunks:
fsync(int),fdatasync(int),sync(void)inuserspace/libc/src/unistd.c; declarations inunistd.h;SYS_FDATASYNCdefine injefeos_syscall.h. - Sysconf honesty:
_SC_FSYNCand_SC_SYNCHRONIZED_IOnow return200809L(the standard value) instead of -1. - synctest: a 6-case regression covering valid-fd-returns-0 for fsync and fdatasync, EBADF for negative and out-of-range fds, sync() callable as void, and an end-to-end open / write / fsync / close / read round-trip. Case 6 SKIPs cleanly if /tmp NTFS write isn't available on a given cold boot (still tracked as task #44 / #64 — a different problem).
Validation
Cold-boot via Jenkins build #919, then SSH to JefeOS:
synctest: case1 fsync(stdout)=0 ok
synctest: case2 fdatasync(stdout)=0 ok
synctest: case3 fsync(-1)=EBADF ok
synctest: case4 fdatasync(9999)=EBADF ok
synctest: case5 sync() returned ok
synctest: case6 SKIP (open /tmp failed errno=1)
synctest: PASS 5 / 6
Five of five syscall-validation cases pass; case 6 SKIPs because of an unrelated NTFS issue. uptime after the run still returns clean — no panic.
Scorecard Impact
Three entries flipped on both kernels: fsync (partial → yes), fdatasync (partial → yes), sync (no → yes). That's +2.0 score per kernel under the dashboard's half-credit-for-partials rubric. Next free native syscall is now 319.
Process Note: Don't Reformat data.json by Accident
First commit of the sprint accidentally expanded docs/posix/data.json from 1707 lines (compact one-per-line) to 9042 lines (verbose multi-line) because a quick json.dump(..., indent=2) Python helper rewrote the whole file. The actual semantic change was three lines. Followed up with a format-restore commit so the diff is greppable. Lesson: when touching data.json, always use a targeted Edit, not a json round-trip.
What's Next
The handoff backlog has more partial → yes candidates that follow this same pattern: fchmod (just needs SYS_FCHMOD), chdir / fchdir (needs per-task cwd state — bigger), the NTFS dir-split refactor for task #65 (relieves heap pressure under /programs/ resolves). Momentum is the goal — keep flipping easy wins while saving the heap-cap fight (task #64) for a session with more runway.