Add tentative fsync wrapper.

Fsync is a POSIX API that may not be available or useful on all systems.
This commit is contained in:
Calvin Rose
2026-03-03 20:16:19 -06:00
parent aa63adccb4
commit 7df23e8070
5 changed files with 50 additions and 7 deletions
+1
View File
@@ -2,6 +2,7 @@
All notable changes to this project will be documented in this file.
## Unreleased - ???
- Add `file/sync` as a wrapper around fsync.
- Documentation fixes
- ev/thread-chan deadlock bug fixed
- Re-add removed support for non-blocking net/connect on windows.
+3 -3
View File
@@ -1722,7 +1722,7 @@ void janet_loop1_impl(int has_timeout, JanetTimestamp to) {
}
if (fiber != NULL) {
fiber->flags &= ~JANET_FIBER_EV_FLAG_IN_FLIGHT;
jo->bytes_transfered = (ULONG_PTR) num_bytes_transferred;
jo->bytes_transferred = (ULONG_PTR) num_bytes_transferred;
fiber->ev_callback(fiber, result ? JANET_ASYNC_EVENT_COMPLETE : JANET_ASYNC_EVENT_FAILED);
} else {
janet_free((void *) jo);
@@ -2472,7 +2472,7 @@ void ev_callback_read(JanetFiber *fiber, JanetAsyncEvent event) {
case JANET_ASYNC_EVENT_FAILED:
case JANET_ASYNC_EVENT_COMPLETE: {
/* Called when read finished */
uint32_t ev_bytes = (uint32_t) state->overlapped.bytes_transfered;
uint32_t ev_bytes = (uint32_t) state->overlapped.bytes_transferred;
state->bytes_read += ev_bytes;
if (state->bytes_read == 0 && (state->mode != JANET_ASYNC_READMODE_RECVFROM)) {
janet_schedule(fiber, janet_wrap_nil());
@@ -2722,7 +2722,7 @@ void ev_callback_write(JanetFiber *fiber, JanetAsyncEvent event) {
case JANET_ASYNC_EVENT_FAILED:
case JANET_ASYNC_EVENT_COMPLETE: {
/* Called when write finished */
uint32_t ev_bytes = (uint32_t) state->overlapped.bytes_transfered;
uint32_t ev_bytes = (uint32_t) state->overlapped.bytes_transferred;
if (ev_bytes == 0 && (state->mode != JANET_ASYNC_WRITEMODE_SENDTO)) {
janet_cancel(fiber, janet_cstringv("disconnect"));
janet_async_end(fiber);
+37
View File
@@ -320,6 +320,41 @@ static int cfun_io_gc(void *p, size_t len) {
return 0;
}
/* Cross-platform fsync binding for Janet */
JANET_CORE_FN(cfun_io_fsync,
"(file/sync f)",
"Flushes all operating system buffers to disk for file `f`. Guarantees data is physically "
"written to disk in a platform-dependent way. Returns the file handle if successful, raises error if not.") {
janet_fixarity(argc, 1);
JanetFile *iof = janet_getabstract(argv, 0, &janet_file_type);
if (iof->flags & JANET_FILE_CLOSED)
janet_panic("file is closed");
#ifdef JANET_WINDOWS
{
intptr_t fd = _fileno(iof->file);
if (fd < 0)
janet_panic("invalid file descriptor");
HANDLE hFile = (HANDLE)_get_osfhandle(fd);
if (hFile == INVALID_HANDLE_VALUE)
janet_panic("invalid file handle");
if (!FlushFileBuffers(hFile))
janet_panic("could not flush file buffers");
}
#elif defined(_POSIX_VERSION)
{
int fd = fileno(iof->file);
if (fd < 0)
janet_panic("invalid file descriptor");
if (fsync(fd) != 0)
janet_panic("could not fsync file");
}
#else
janet_panic("fsync not supported on this platform");
#endif
return argv[0];
}
/* Close a file */
JANET_CORE_FN(cfun_io_fclose,
"(file/close f)",
@@ -394,6 +429,7 @@ static JanetMethod io_file_methods[] = {
{"seek", cfun_io_fseek},
{"tell", cfun_io_ftell},
{"write", cfun_io_fwrite},
{"sync", cfun_io_fsync},
{NULL, NULL}
};
@@ -846,6 +882,7 @@ void janet_lib_io(JanetTable *env) {
JANET_CORE_REG("file/flush", cfun_io_fflush),
JANET_CORE_REG("file/seek", cfun_io_fseek),
JANET_CORE_REG("file/tell", cfun_io_ftell),
JANET_CORE_REG("file/sync", cfun_io_fsync),
JANET_REG_END
};
janet_core_cfuns_ext(env, NULL, io_cfuns);
+1 -1
View File
@@ -213,7 +213,7 @@ typedef struct {
OVERLAPPED overlapped;
WSAOVERLAPPED wsaoverlapped;
} as;
uint32_t bytes_transfered;
uint32_t bytes_transferred;
} JanetOverlapped;
#endif
#endif
+8 -3
View File
@@ -55,7 +55,8 @@
(file/flush f)
(file/seek f :set 0)
(assert (= 0 (file/tell f)) "start of file again")
(assert (= (string (file/read f :all)) "foo\n") "temp files work"))
(assert (= (string (file/read f :all)) "foo\n") "temp files work")
(assert-no-error "fsync" (file/sync f)))
# issue #1055 - 2c927ea76
(let [b @""]
@@ -74,9 +75,13 @@
(defn to-b [a] (buffer/push b a))
(xprintf to-b "123")
(assert (deep= b @"123\n") "xprintf to buffer")
(assert-error "cannot print to 3" (xprintf 3 "123"))
# file/sync
(with [f (file/temp "wb")]
(file/write f "123abc")
(file/flush f)
(file/sync f))
(end-suite)