diff --git a/src/library_wasmfs_opfs.js b/src/library_wasmfs_opfs.js index 99ebc3da3c494..a0fe22b56b308 100644 --- a/src/library_wasmfs_opfs.js +++ b/src/library_wasmfs_opfs.js @@ -402,10 +402,14 @@ mergeInto(LibraryManager.library, { }, _wasmfs_opfs_flush_access__deps: ['$wasmfsOPFSAccessHandles'], - _wasmfs_opfs_flush_access: async function(ctx, accessID) { + _wasmfs_opfs_flush_access: async function(ctx, accessID, errPtr) { let accessHandle = wasmfsOPFSAccessHandles.get(accessID); - // TODO: Error handling - await accessHandle.flush(); + try { + await accessHandle.flush(); + } catch { + let err = -{{{ cDefine('EIO') }}}; + {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; + } _emscripten_proxy_finish(ctx); } }); diff --git a/system/lib/wasmfs/backends/node_backend.cpp b/system/lib/wasmfs/backends/node_backend.cpp index 35f4d2169e382..9e9d7c4906e3e 100644 --- a/system/lib/wasmfs/backends/node_backend.cpp +++ b/system/lib/wasmfs/backends/node_backend.cpp @@ -179,7 +179,7 @@ class NodeFile : public DataFile { return nwritten; } - void flush() override { + int flush() override { WASMFS_UNREACHABLE("TODO: implement NodeFile::flush"); } }; diff --git a/system/lib/wasmfs/backends/opfs_backend.cpp b/system/lib/wasmfs/backends/opfs_backend.cpp index d69b82cca0637..23136ffc2a422 100644 --- a/system/lib/wasmfs/backends/opfs_backend.cpp +++ b/system/lib/wasmfs/backends/opfs_backend.cpp @@ -107,7 +107,7 @@ void _wasmfs_opfs_set_size_file(em_proxying_ctx* ctx, uint32_t size, int* err); -void _wasmfs_opfs_flush_access(em_proxying_ctx* ctx, int access_id); +void _wasmfs_opfs_flush_access(em_proxying_ctx* ctx, int access_id, int* err); } // extern "C" @@ -313,11 +313,12 @@ class OPFSFile : public DataFile { return nwritten; } - void flush() override { + int flush() override { + int err = 0; switch (state.getKind()) { case OpenState::Access: proxy([&](auto ctx) { - _wasmfs_opfs_flush_access(ctx.ctx, state.getAccessID()); + _wasmfs_opfs_flush_access(ctx.ctx, state.getAccessID(), &err); }); break; case OpenState::Blob: @@ -325,6 +326,7 @@ class OPFSFile : public DataFile { default: break; } + return err; } }; diff --git a/system/lib/wasmfs/backends/proxied_file_backend.cpp b/system/lib/wasmfs/backends/proxied_file_backend.cpp index 7c46e75babe7d..07e78930d8a28 100644 --- a/system/lib/wasmfs/backends/proxied_file_backend.cpp +++ b/system/lib/wasmfs/backends/proxied_file_backend.cpp @@ -47,7 +47,7 @@ class ProxiedFile : public DataFile { return result; } - void flush() override {} + int flush() override { return 0; } // Querying the size of the Proxied File returns the size of the underlying // file given by the proxying mechanism. diff --git a/system/lib/wasmfs/file.h b/system/lib/wasmfs/file.h index 32937e714c284..84fe5635df8a6 100644 --- a/system/lib/wasmfs/file.h +++ b/system/lib/wasmfs/file.h @@ -146,8 +146,9 @@ class DataFile : public File { // opened. Returns 0 on success or a negative error code. virtual int setSize(size_t size) = 0; - // TODO: Design a proper API for flushing files. - virtual void flush() = 0; + // Sync the file data to the underlying persistent storage, if any. Returns 0 + // on success or a negative error code. + virtual int flush() = 0; public: static constexpr FileKind expectedKind = File::DataFileKind; @@ -327,7 +328,7 @@ class DataFile::Handle : public File::Handle { [[nodiscard]] int setSize(size_t size) { return getFile()->setSize(size); } // TODO: Design a proper API for flushing files. - void flush() { getFile()->flush(); } + [[nodiscard]] int flush() { return getFile()->flush(); } // This function loads preloaded files from JS Memory into this DataFile. // TODO: Make this virtual so specific backends can specialize it for better diff --git a/system/lib/wasmfs/js_impl_backend.h b/system/lib/wasmfs/js_impl_backend.h index 97b2d64974627..fe66b9a04de4e 100644 --- a/system/lib/wasmfs/js_impl_backend.h +++ b/system/lib/wasmfs/js_impl_backend.h @@ -94,7 +94,7 @@ class JSImplFile : public DataFile { getBackendIndex(), getFileIndex(), buf, len, offset); } - void flush() override {} + int flush() override { return 0; } size_t getSize() override { return _wasmfs_jsimpl_get_size(getBackendIndex(), getFileIndex()); diff --git a/system/lib/wasmfs/memory_backend.h b/system/lib/wasmfs/memory_backend.h index 24c0b3138376f..7965ad49da43a 100644 --- a/system/lib/wasmfs/memory_backend.h +++ b/system/lib/wasmfs/memory_backend.h @@ -23,7 +23,7 @@ class MemoryFile : public DataFile { int close() override { return 0; } ssize_t write(const uint8_t* buf, size_t len, off_t offset) override; ssize_t read(uint8_t* buf, size_t len, off_t offset) override; - void flush() override {} + int flush() override { return 0; } size_t getSize() override { return buffer.size(); } int setSize(size_t size) override { buffer.resize(size); diff --git a/system/lib/wasmfs/pipe_backend.h b/system/lib/wasmfs/pipe_backend.h index e36778e6bfa60..105d93531e73f 100644 --- a/system/lib/wasmfs/pipe_backend.h +++ b/system/lib/wasmfs/pipe_backend.h @@ -44,7 +44,7 @@ class PipeFile : public DataFile { return len; } - void flush() override {} + int flush() override { return 0; } size_t getSize() override { return data->size(); } diff --git a/system/lib/wasmfs/proxied_async_js_impl_backend.h b/system/lib/wasmfs/proxied_async_js_impl_backend.h index 0aad7e7fbc003..025c85abbcca1 100644 --- a/system/lib/wasmfs/proxied_async_js_impl_backend.h +++ b/system/lib/wasmfs/proxied_async_js_impl_backend.h @@ -106,7 +106,7 @@ class ProxiedAsyncJSImplFile : public DataFile { return result; } - void flush() override {} + int flush() override { return 0; } size_t getSize() override { size_t result; diff --git a/system/lib/wasmfs/special_files.cpp b/system/lib/wasmfs/special_files.cpp index de7c3cac15fea..a00eb72c10fe4 100644 --- a/system/lib/wasmfs/special_files.cpp +++ b/system/lib/wasmfs/special_files.cpp @@ -28,7 +28,7 @@ class NullFile : public DataFile { ssize_t read(uint8_t* buf, size_t len, off_t offset) override { return 0; } - void flush() override {} + int flush() override { return 0; } size_t getSize() override { return 0; } int setSize(size_t size) override { return -EPERM; } @@ -49,7 +49,7 @@ class StdinFile : public DataFile { abort(); }; - void flush() override {} + int flush() override { return 0; } size_t getSize() override { return 0; } int setSize(size_t size) override { return -EPERM; } @@ -69,12 +69,13 @@ class WritingStdFile : public DataFile { return -__WASI_ERRNO_INVAL; }; - void flush() override { + int flush() override { // Write a null to flush the output if we have content. if (!writeBuffer.empty()) { const uint8_t nothing = '\0'; write(¬hing, 1, 0); } + return 0; } size_t getSize() override { return 0; } @@ -150,7 +151,7 @@ class RandomFile : public DataFile { return len; }; - void flush() override {} + int flush() override { return 0; } size_t getSize() override { return 0; } int setSize(size_t size) override { return -EPERM; } diff --git a/system/lib/wasmfs/syscalls.cpp b/system/lib/wasmfs/syscalls.cpp index 09aa9ab858161..92b5b8356fa13 100644 --- a/system/lib/wasmfs/syscalls.cpp +++ b/system/lib/wasmfs/syscalls.cpp @@ -292,7 +292,8 @@ __wasi_errno_t __wasi_fd_sync(__wasi_fd_t fd) { // way. TODO: in the future we may want syncing of directories. auto dataFile = openFile->locked().getFile()->dynCast(); if (dataFile) { - dataFile->locked().flush(); + // Translate to WASI standard of positive return codes. + return -dataFile->locked().flush(); } return __WASI_ERRNO_SUCCESS; diff --git a/system/lib/wasmfs/wasmfs.cpp b/system/lib/wasmfs/wasmfs.cpp index 011896b23bdd3..6cdf062836ff9 100644 --- a/system/lib/wasmfs/wasmfs.cpp +++ b/system/lib/wasmfs/wasmfs.cpp @@ -58,8 +58,8 @@ WasmFS::~WasmFS() { // Note that we lock here, although strictly speaking it is unnecessary given // that we are in the destructor of WasmFS: nothing can possibly be running // on files at this time. - SpecialFiles::getStdout()->locked().flush(); - SpecialFiles::getStderr()->locked().flush(); + (void)SpecialFiles::getStdout()->locked().flush(); + (void)SpecialFiles::getStderr()->locked().flush(); // Break the reference cycle caused by the root directory being its own // parent.