From 5074dbff99c13f2a430074c2e4d5cc810979efbe Mon Sep 17 00:00:00 2001 From: "Andrei I. Holub" Date: Fri, 10 Jul 2026 21:46:54 -0400 Subject: [PATCH] Fix Emscripten 6 compatibility: restore ERRNO_CODES and bind FS method context Emscripten 6 made two breaking changes that break BrowserFS's EmscriptenFS shim: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. ERRNO_CODES is no longer a global (removed in emscripten >=3.x). Pass FS, PATH, and an explicit errno map to EmscriptenFS so BrowserFS can map errno names to numbers. 2. FS node_ops/stream_ops methods are now called as bare functions (e.g. getattr(node) instead of node_ops.getattr(node)), losing . Bind all prototype methods on the node_ops and stream_ops wrapper instances so they retain their context. Without these fixes, accessing files under /emulator throws: TypeError: can't access property fs, this is undefined at $.getattr → fstat → ___syscall_fstat64 --- loader.js | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/loader.js b/loader.js index 74d302ba..6251bd54 100644 --- a/loader.js +++ b/loader.js @@ -1273,7 +1273,39 @@ var Module = null; preInit: function () { // Re-initialize BFS to just use the writable in-memory storage. BrowserFS.initialize(game_data.fs); - var BFS = new BrowserFS.EmscriptenFS(); + // Newer emscripten (>=3.x) no longer exposes ERRNO_CODES as a + // global, and FS/PATH are module-scoped vars that happen to be + // globals because mame.js is a plain top-level script. Pass them + // explicitly to EmscriptenFS so BrowserFS can map node errno + // names (e.g. ENOENT) to numbers. + var ERRNO_CODES_MAP = { + EPERM: 1, ENOENT: 2, ESRCH: 3, EINTR: 4, EIO: 5, ENXIO: 6, + E2BIG: 7, ENOEXEC: 8, EBADF: 9, ECHILD: 10, EAGAIN: 11, + ENOMEM: 12, EACCES: 13, EFAULT: 14, EBUSY: 16, EEXIST: 17, + EXDEV: 18, ENODEV: 19, ENOTDIR: 20, EISDIR: 21, EINVAL: 22, + ENFILE: 23, EMFILE: 24, ENOTTY: 25, ETXTBSY: 26, EFBIG: 27, + ENOSPC: 28, ESPIPE: 29, EROFS: 30, EMLINK: 31, EPIPE: 32, + EDOM: 33, ERANGE: 34, ENOTEMPTY: 39, ELOOP: 40, + ENAMETOOLONG: 37, ENOSYS: 38 + }; + var BFS = new BrowserFS.EmscriptenFS(FS, PATH, ERRNO_CODES_MAP); + // Emscripten 6+ extracts node_ops/stream_ops methods and + // calls them as bare functions (e.g. getattr(node) instead + // of node_ops.getattr(node)), losing `this`. Bind every + // method on the node_ops and stream_ops wrapper objects so + // they retain their context regardless of call convention. + ["node_ops", "stream_ops"].forEach(function (key) { + var ops = BFS[key]; + if (!ops) return; + Object.getOwnPropertyNames( + Object.getPrototypeOf(ops) + ).forEach(function (name) { + if (name !== "constructor" && + typeof ops[name] === "function") { + ops[name] = ops[name].bind(ops); + } + }); + }); // Mount the file system into Emscripten. FS.mkdir('/emulator'); FS.mount(BFS, {root: '/'}, '/emulator');