From 83790a7332d2021d38a80b37cc5219caa622c370 Mon Sep 17 00:00:00 2001 From: walshal Date: Mon, 23 Feb 2026 17:19:09 -0800 Subject: [PATCH 01/12] Overwrite same-name CASE_INSENSITIVE files (#26327) Signed-off-by: walshal --- src/lib/libfs.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/lib/libfs.js b/src/lib/libfs.js index 8f3c1a430b23f..42786eea2d21e 100644 --- a/src/lib/libfs.js +++ b/src/lib/libfs.js @@ -698,12 +698,23 @@ FS.staticInit();`; throw new FS.ErrnoError({{{ cDefs.EEXIST }}}); } var errCode = FS.mayCreate(parent, name); +#if CASE_INSENSITIVE_FS + if (errCode && errCode !== {{{ cDefs.EEXIST }}}) { +#else if (errCode) { +#endif throw new FS.ErrnoError(errCode); } if (!parent.node_ops.mknod) { throw new FS.ErrnoError({{{ cDefs.EPERM }}}); } +#if CASE_INSENSITIVE_FS + if(errCode === {{{ cDefs.EEXIST }}}) { + var oldNodeLookup = FS.lookupPath(path); + var oldNode = oldNodeLookup.node; + FS.destroyNode(oldNode); + } +#endif return parent.node_ops.mknod(parent, name, mode, dev); }, statfs(path) { From 2841fba43e99487fc96838b53a1a3293c91b5ef7 Mon Sep 17 00:00:00 2001 From: walshal Date: Sat, 28 Feb 2026 11:46:22 -0800 Subject: [PATCH 02/12] Add Case Insensitive Overwrite Test (#15245) --- test/test_core.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test_core.py b/test/test_core.py index 9599dd13b86ce..1cfcb7bf1bdaf 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -5969,6 +5969,8 @@ def test_fs_readv(self): @also_with_noderawfs def test_fs_writev(self): self.do_runf('fs/test_writev.c', 'success', cflags=['-sFORCE_FILESYSTEM']) + self.do_runf('fs/test_case_insensitive.c', 'success', cflags=['-sFORCE_FILESYSTEM', '-sCASE_INSENSITIVE_FS']) + def test_fs_64bit(self): if self.get_setting('WASMFS'): From 69b327c0a1b143762a30d6efe211903ee42984b8 Mon Sep 17 00:00:00 2001 From: walshal Date: Sat, 28 Feb 2026 12:48:05 -0800 Subject: [PATCH 03/12] Add test code --- test/fs/test_case_insensitive.c | 47 +++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 test/fs/test_case_insensitive.c diff --git a/test/fs/test_case_insensitive.c b/test/fs/test_case_insensitive.c new file mode 100644 index 0000000000000..76a32bdc40cea --- /dev/null +++ b/test/fs/test_case_insensitive.c @@ -0,0 +1,47 @@ +/* + * Copyright 2026 The Emscripten Authors. All rights reserved. + * Emscripten is available under two separate licenses, the MIT license and the + * University of Illinois/NCSA Open Source License. Both these licenses can be + * found in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include +#include + +int main() { + int fd = open("testfile", O_CREAT | O_TRUNC | O_RDWR, S_IRWXU); + assert(fd >= 0); + + char buf0[16] = "a=1\n"; + char buf1[] = "b=2\n"; + struct iovec iov[] = {{.iov_base = buf0, .iov_len = 4}, + {.iov_base = buf1, .iov_len = 4}}; + ssize_t nwritten = pwritev(fd, iov, 2, 0); + assert(nwritten == 8); + close(fd); + + int fd2 = open("teStfIle", O_CREAT | O_TRUNC | O_RDWR, S_IRWXU); + assert(fd >= 0); + + char buf3[16] = "a=3\n"; + char buf4[] = "b=4\n"; + struct iovec iov2[] = {{.iov_base = buf3, .iov_len = 4}, + {.iov_base = buf4, .iov_len = 4}}; + ssize_t nwritten2 = pwritev(fd2, iov2, 2, 0); + assert(nwritten2 == 8); + close(fd2); + + int fd3 = open("testfile", O_RDONLY); + size_t nread = read(fd, buf0, sizeof(buf0)); + assert(nread == 8); + assert(strcmp(buf0, "a=3\nb=4\n") == 0); + close(fd); + + printf("success\n"); + return 0; +} From 9a4f36fb8554ad6ca7117a0ddfaa6ee53612dde5 Mon Sep 17 00:00:00 2001 From: walshal Date: Wed, 4 Mar 2026 11:00:47 -0800 Subject: [PATCH 04/12] Add test for #26327 Added a test that fails when preloaded files cause the JS to hang Addressed space after if from code review in PR Removed test_case_insensitive (does not test what I expected it to) Signed-off-by: walshal --- src/lib/libfs.js | 2 +- test/fs/test_case_insensitive.c | 47 --------------------------------- test/fs/test_insensitive_hang.c | 41 ++++++++++++++++++++++++++++ test/test_core.py | 9 ++++++- 4 files changed, 50 insertions(+), 49 deletions(-) delete mode 100644 test/fs/test_case_insensitive.c create mode 100644 test/fs/test_insensitive_hang.c diff --git a/src/lib/libfs.js b/src/lib/libfs.js index 42786eea2d21e..12a2d3f451b38 100644 --- a/src/lib/libfs.js +++ b/src/lib/libfs.js @@ -709,7 +709,7 @@ FS.staticInit();`; throw new FS.ErrnoError({{{ cDefs.EPERM }}}); } #if CASE_INSENSITIVE_FS - if(errCode === {{{ cDefs.EEXIST }}}) { + if (errCode === {{{ cDefs.EEXIST }}}) { var oldNodeLookup = FS.lookupPath(path); var oldNode = oldNodeLookup.node; FS.destroyNode(oldNode); diff --git a/test/fs/test_case_insensitive.c b/test/fs/test_case_insensitive.c deleted file mode 100644 index 76a32bdc40cea..0000000000000 --- a/test/fs/test_case_insensitive.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2026 The Emscripten Authors. All rights reserved. - * Emscripten is available under two separate licenses, the MIT license and the - * University of Illinois/NCSA Open Source License. Both these licenses can be - * found in the LICENSE file. - */ - -#include -#include -#include -#include -#include -#include -#include - -int main() { - int fd = open("testfile", O_CREAT | O_TRUNC | O_RDWR, S_IRWXU); - assert(fd >= 0); - - char buf0[16] = "a=1\n"; - char buf1[] = "b=2\n"; - struct iovec iov[] = {{.iov_base = buf0, .iov_len = 4}, - {.iov_base = buf1, .iov_len = 4}}; - ssize_t nwritten = pwritev(fd, iov, 2, 0); - assert(nwritten == 8); - close(fd); - - int fd2 = open("teStfIle", O_CREAT | O_TRUNC | O_RDWR, S_IRWXU); - assert(fd >= 0); - - char buf3[16] = "a=3\n"; - char buf4[] = "b=4\n"; - struct iovec iov2[] = {{.iov_base = buf3, .iov_len = 4}, - {.iov_base = buf4, .iov_len = 4}}; - ssize_t nwritten2 = pwritev(fd2, iov2, 2, 0); - assert(nwritten2 == 8); - close(fd2); - - int fd3 = open("testfile", O_RDONLY); - size_t nread = read(fd, buf0, sizeof(buf0)); - assert(nread == 8); - assert(strcmp(buf0, "a=3\nb=4\n") == 0); - close(fd); - - printf("success\n"); - return 0; -} diff --git a/test/fs/test_insensitive_hang.c b/test/fs/test_insensitive_hang.c new file mode 100644 index 0000000000000..c6446dded35db --- /dev/null +++ b/test/fs/test_insensitive_hang.c @@ -0,0 +1,41 @@ +/* + * Copyright 2026 The Emscripten Authors. All rights reserved. + * Emscripten is available under two separate licenses, the MIT license and the + * University of Illinois/NCSA Open Source License. Both these licenses can be + * found in the LICENSE file. + */ + +#include +#include + +#include + + +void loadScript() { + printf("load2"); + FILE *file = fopen("file1.txt", "r"); + + if (!file) { + assert(false); + } + + while (!feof(file)) { + char c = fgetc(file); + if (c != EOF) { + putchar(c); + } + } + fclose (file); + exit(0); +} + +void scriptLoadFail() { + printf("failed to load second script\n"); + assert(false); +} + + +int main() { + emscripten_async_load_script("script.js", loadScript, scriptLoadFail); + return 99; +} diff --git a/test/test_core.py b/test/test_core.py index 1cfcb7bf1bdaf..46aedcd615dc0 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -5969,7 +5969,14 @@ def test_fs_readv(self): @also_with_noderawfs def test_fs_writev(self): self.do_runf('fs/test_writev.c', 'success', cflags=['-sFORCE_FILESYSTEM']) - self.do_runf('fs/test_case_insensitive.c', 'success', cflags=['-sFORCE_FILESYSTEM', '-sCASE_INSENSITIVE_FS']) + + def test_insensitive_hang(self): + create_file('file1.txt', 'one') + create_file('fILe1.txt', 'two') + # `--from-emcc` needed here otherwise the output defines `var Module =` which will shadow the + # global `Module`. + self.run_process([FILE_PACKAGER, 'test.data', '--preload', 'file1.txt', 'fILe1.txt', '--from-emcc', '--js-output=script.js']) + self.do_runf('fs/test_insensitive_hang.c', cflags=['-sFORCE_FILESYSTEM', '-sCASE_INSENSITIVE_FS']) def test_fs_64bit(self): From 1d1e6f0f825ecd6b9020e3e61eebab1287bc8762 Mon Sep 17 00:00:00 2001 From: walshal Date: Wed, 4 Mar 2026 15:28:03 -0800 Subject: [PATCH 05/12] Write improved test for #15245 Adds test_insensitive_overwrite test to ensure, in case insensitive filesystems, inaccessible prior versions of files are not left around after overwrite Signed-off-by: walshal --- test/fs/test_insensitive_overwrite.c | 11 +++++++++++ test/fs/test_insensitive_overwrite.js | 6 ++++++ test/fs/test_insensitive_overwrite.out | 2 ++ test/test_core.py | 5 +++++ 4 files changed, 24 insertions(+) create mode 100644 test/fs/test_insensitive_overwrite.c create mode 100644 test/fs/test_insensitive_overwrite.js create mode 100644 test/fs/test_insensitive_overwrite.out diff --git a/test/fs/test_insensitive_overwrite.c b/test/fs/test_insensitive_overwrite.c new file mode 100644 index 0000000000000..b452dd52595dc --- /dev/null +++ b/test/fs/test_insensitive_overwrite.c @@ -0,0 +1,11 @@ +/* + * Copyright 2026 The Emscripten Authors. All rights reserved. + * Emscripten is available under two separate licenses, the MIT license and the + * University of Illinois/NCSA Open Source License. Both these licenses can be + * found in the LICENSE file. + */ + +int main() { + // Nothing to do here. Test is written in JS. See test/fs/test_insensitive_overwrite.js. + return 0; +} diff --git a/test/fs/test_insensitive_overwrite.js b/test/fs/test_insensitive_overwrite.js new file mode 100644 index 0000000000000..1640161b46ccd --- /dev/null +++ b/test/fs/test_insensitive_overwrite.js @@ -0,0 +1,6 @@ +FS.createDataFile('/', "file.txt", "foo"); +FS.createDataFile('/', "fILe.txt", "foo2"); +var fileContents = FS.readFile("/file.txt"); +out('file.txt: ' + fileContents); +var ret = FS.analyzePath('/file.txt'); +out('file.txt collison: ' + ret.object.name_next); diff --git a/test/fs/test_insensitive_overwrite.out b/test/fs/test_insensitive_overwrite.out new file mode 100644 index 0000000000000..f461184a3640d --- /dev/null +++ b/test/fs/test_insensitive_overwrite.out @@ -0,0 +1,2 @@ +file.txt: 102,111,111,50 +file.txt collison: undefined diff --git a/test/test_core.py b/test/test_core.py index 46aedcd615dc0..04180760069c2 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -5978,6 +5978,11 @@ def test_insensitive_hang(self): self.run_process([FILE_PACKAGER, 'test.data', '--preload', 'file1.txt', 'fILe1.txt', '--from-emcc', '--js-output=script.js']) self.do_runf('fs/test_insensitive_hang.c', cflags=['-sFORCE_FILESYSTEM', '-sCASE_INSENSITIVE_FS']) + def test_insensitive_overwrite(self): + self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', ['$FS']) + self.set_setting('CASE_INSENSITIVE_FS', ['1']) + self.add_pre_run(read_file(test_file('fs/test_insensitive_overwrite.js'))) + self.do_run_in_out_file_test('fs/test_insensitive_overwrite.c') def test_fs_64bit(self): if self.get_setting('WASMFS'): From 519a05d41e394adc7d81417e7fb831ffc52bdf7a Mon Sep 17 00:00:00 2001 From: walshal Date: Wed, 4 Mar 2026 16:45:12 -0800 Subject: [PATCH 06/12] Files with identical contents no longer overwrite Add catch for throws coming out of file packager's async FS_createDataFile Add overwrite behavior to createDataFile instead of mknod so it can throw an EEXISTS error up if the files have the exact same data Add check for skipping duplicate node creation to the test_insensitive_overwrite test Signed-off-by: walshal --- src/lib/libfs.js | 40 +++++++++++++++++++------- test/fs/test_insensitive_overwrite.js | 7 +++++ test/fs/test_insensitive_overwrite.out | 1 + tools/file_packager.py | 7 ++++- 4 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/lib/libfs.js b/src/lib/libfs.js index 12a2d3f451b38..8b23224f5b257 100644 --- a/src/lib/libfs.js +++ b/src/lib/libfs.js @@ -698,23 +698,12 @@ FS.staticInit();`; throw new FS.ErrnoError({{{ cDefs.EEXIST }}}); } var errCode = FS.mayCreate(parent, name); -#if CASE_INSENSITIVE_FS - if (errCode && errCode !== {{{ cDefs.EEXIST }}}) { -#else if (errCode) { -#endif throw new FS.ErrnoError(errCode); } if (!parent.node_ops.mknod) { throw new FS.ErrnoError({{{ cDefs.EPERM }}}); } -#if CASE_INSENSITIVE_FS - if (errCode === {{{ cDefs.EEXIST }}}) { - var oldNodeLookup = FS.lookupPath(path); - var oldNode = oldNodeLookup.node; - FS.destroyNode(oldNode); - } -#endif return parent.node_ops.mknod(parent, name, mode, dev); }, statfs(path) { @@ -1622,7 +1611,36 @@ FS.staticInit();`; path = name ? PATH.join2(parent, name) : parent; } var mode = FS_getMode(canRead, canWrite); +#if CASE_INSENSITIVE_FS + try { +#endif var node = FS.create(path, mode); +#if CASE_INSENSITIVE_FS + } catch (e) { + if (e.errno === {{{ cDefs.EEXIST }}}) { + var oldNodeLookup = FS.lookupPath(path); + var oldNode = oldNodeLookup.node; + if (data.length === oldNode.contents.length) { + var isDup = true; + for (var i = 0; i < data.length; i++) { + var currData = data[i]; + if (typeof data == 'string') { + currData = data.charCodeAt(i); + } + if (currData !== oldNode.contents[i]) { + isDup = false; + break; + } + } + if (isDup) { + throw e; + } + } + FS.destroyNode(oldNode); + node = FS.create(path, mode); + } + } +#endif if (data) { if (typeof data == 'string') { var arr = new Array(data.length); diff --git a/test/fs/test_insensitive_overwrite.js b/test/fs/test_insensitive_overwrite.js index 1640161b46ccd..bfc4a08fa1c0b 100644 --- a/test/fs/test_insensitive_overwrite.js +++ b/test/fs/test_insensitive_overwrite.js @@ -4,3 +4,10 @@ var fileContents = FS.readFile("/file.txt"); out('file.txt: ' + fileContents); var ret = FS.analyzePath('/file.txt'); out('file.txt collison: ' + ret.object.name_next); +var errCode = 0; +try { + FS.createDataFile('/', "FIlE.txt", "foo2"); +} catch(e) { + errCode = e.errno; +} +out('errorCode: ' + errCode); diff --git a/test/fs/test_insensitive_overwrite.out b/test/fs/test_insensitive_overwrite.out index f461184a3640d..7b39a962c7dd9 100644 --- a/test/fs/test_insensitive_overwrite.out +++ b/test/fs/test_insensitive_overwrite.out @@ -1,2 +1,3 @@ file.txt: 102,111,111,50 file.txt collison: undefined +errorCode: 20 diff --git a/tools/file_packager.py b/tools/file_packager.py index daaceaec352b4..fdc47ca4fd882 100755 --- a/tools/file_packager.py +++ b/tools/file_packager.py @@ -683,8 +683,13 @@ def generate_preload_js(data_target, data_files, metadata): } catch (e) { err(`Preloading file ${name} failed`, e); }\n''' - create_data = '''// canOwn this data in the filesystem, it is a slice into the heap that will never change + create_data = ''' + try { + // canOwn this data in the filesystem, it is a slice into the heap that will never change Module['FS_createDataFile'](name, null, data, true, true, true); + } catch(e) { + err(`Preloading file ${name} failed`, e); + }\n Module['removeRunDependency'](`fp ${name}`);''' finish_handler = create_preloaded if options.use_preload_plugins else create_data From b95f5245828ab3b4fdaee2e2f4a8330cda81ab81 Mon Sep 17 00:00:00 2001 From: walshal Date: Thu, 5 Mar 2026 15:20:38 -0800 Subject: [PATCH 07/12] Fix failing CI Fix for test_file_packager Fix for test_insensitive_hang in instance and esm_integration Signed-off-by: walshal --- test/test_core.py | 1 + tools/file_packager.py | 9 ++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/test_core.py b/test/test_core.py index 04180760069c2..52a1e07264b61 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -5970,6 +5970,7 @@ def test_fs_readv(self): def test_fs_writev(self): self.do_runf('fs/test_writev.c', 'success', cflags=['-sFORCE_FILESYSTEM']) + @no_modularize_instance('uses Module object directly') def test_insensitive_hang(self): create_file('file1.txt', 'one') create_file('fILe1.txt', 'two') diff --git a/tools/file_packager.py b/tools/file_packager.py index fdc47ca4fd882..2af63ecf15b7a 100755 --- a/tools/file_packager.py +++ b/tools/file_packager.py @@ -683,13 +683,12 @@ def generate_preload_js(data_target, data_files, metadata): } catch (e) { err(`Preloading file ${name} failed`, e); }\n''' - create_data = ''' - try { - // canOwn this data in the filesystem, it is a slice into the heap that will never change - Module['FS_createDataFile'](name, null, data, true, true, true); + create_data = '''try { + // canOwn this data in the filesystem, it is a slice into the heap that will never change + Module['FS_createDataFile'](name, null, data, true, true, true); } catch(e) { err(`Preloading file ${name} failed`, e); - }\n + } Module['removeRunDependency'](`fp ${name}`);''' finish_handler = create_preloaded if options.use_preload_plugins else create_data From dbafd477180a055823264098ecc2ea5e66e3b7f6 Mon Sep 17 00:00:00 2001 From: walshal Date: Thu, 5 Mar 2026 17:08:21 -0800 Subject: [PATCH 08/12] Fix typos Fix typos as indicated by clang-format in C and JS files Signed-off-by: walshal --- AUTHORS | 1 + test/fs/test_insensitive_hang.c | 6 ++---- test/fs/test_insensitive_overwrite.c | 3 ++- test/fs/test_insensitive_overwrite.js | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/AUTHORS b/AUTHORS index 3baa0068ef86b..ffb728e0258ab 100644 --- a/AUTHORS +++ b/AUTHORS @@ -602,3 +602,4 @@ a license to everyone to use it as detailed in LICENSE.) * Christian Lloyd (copyright owned by Teladoc Health, Inc.) * Sean Morris * Mitchell Wills (copyright owned by Google, Inc.) +* Alex Walsh (alexwalsh6x7@gmail.com> diff --git a/test/fs/test_insensitive_hang.c b/test/fs/test_insensitive_hang.c index c6446dded35db..37ceb6be7674a 100644 --- a/test/fs/test_insensitive_hang.c +++ b/test/fs/test_insensitive_hang.c @@ -10,10 +10,9 @@ #include - void loadScript() { printf("load2"); - FILE *file = fopen("file1.txt", "r"); + FILE* file = fopen("file1.txt", "r"); if (!file) { assert(false); @@ -25,7 +24,7 @@ void loadScript() { putchar(c); } } - fclose (file); + fclose(file); exit(0); } @@ -34,7 +33,6 @@ void scriptLoadFail() { assert(false); } - int main() { emscripten_async_load_script("script.js", loadScript, scriptLoadFail); return 99; diff --git a/test/fs/test_insensitive_overwrite.c b/test/fs/test_insensitive_overwrite.c index b452dd52595dc..57db8d9f47583 100644 --- a/test/fs/test_insensitive_overwrite.c +++ b/test/fs/test_insensitive_overwrite.c @@ -6,6 +6,7 @@ */ int main() { - // Nothing to do here. Test is written in JS. See test/fs/test_insensitive_overwrite.js. + // Nothing to do here. Test is written in JS. See + // test/fs/test_insensitive_overwrite.js. return 0; } diff --git a/test/fs/test_insensitive_overwrite.js b/test/fs/test_insensitive_overwrite.js index bfc4a08fa1c0b..13614faeba0a2 100644 --- a/test/fs/test_insensitive_overwrite.js +++ b/test/fs/test_insensitive_overwrite.js @@ -7,7 +7,7 @@ out('file.txt collison: ' + ret.object.name_next); var errCode = 0; try { FS.createDataFile('/', "FIlE.txt", "foo2"); -} catch(e) { +} catch (e) { errCode = e.errno; } out('errorCode: ' + errCode); From 97524da2abc98ff64474cdf2efad1d832b97a7e0 Mon Sep 17 00:00:00 2001 From: walshal Date: Fri, 6 Mar 2026 09:49:40 -0800 Subject: [PATCH 09/12] Refactor tests and FS data comparison test_insensitive_hang renamed to test_crash_icase, moved to other, and given windows-only and macos-only flags as they have/can have case-insensitive filesystems by default test_insensitive_overwrite renamed to test_overwrite_icase, and moved to other createDataFile now converts its data to its storage form (char -> char code) before creating the FS node, simplifying data comparison and avoiding duplicated efforts Signed-off-by: walshal --- src/lib/libfs.js | 18 ++++++++---------- .../test_crash_icase.c} | 4 ++-- .../test_overwrite_icase.c} | 0 .../test_overwrite_icase.js} | 0 .../test_overwrite_icase.out} | 0 test/test_core.py | 15 --------------- test/test_other.py | 14 ++++++++++++++ 7 files changed, 24 insertions(+), 27 deletions(-) rename test/{fs/test_insensitive_hang.c => other/test_crash_icase.c} (84%) rename test/{fs/test_insensitive_overwrite.c => other/test_overwrite_icase.c} (100%) rename test/{fs/test_insensitive_overwrite.js => other/test_overwrite_icase.js} (100%) rename test/{fs/test_insensitive_overwrite.out => other/test_overwrite_icase.out} (100%) diff --git a/src/lib/libfs.js b/src/lib/libfs.js index 8b23224f5b257..eba601aaf6a7e 100644 --- a/src/lib/libfs.js +++ b/src/lib/libfs.js @@ -1611,6 +1611,13 @@ FS.staticInit();`; path = name ? PATH.join2(parent, name) : parent; } var mode = FS_getMode(canRead, canWrite); + if (data) { + if (typeof data == 'string') { + var arr = new Array(data.length); + for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i); + data = arr; + } + } #if CASE_INSENSITIVE_FS try { #endif @@ -1623,11 +1630,7 @@ FS.staticInit();`; if (data.length === oldNode.contents.length) { var isDup = true; for (var i = 0; i < data.length; i++) { - var currData = data[i]; - if (typeof data == 'string') { - currData = data.charCodeAt(i); - } - if (currData !== oldNode.contents[i]) { + if (data[i] !== oldNode.contents[i]) { isDup = false; break; } @@ -1642,11 +1645,6 @@ FS.staticInit();`; } #endif if (data) { - if (typeof data == 'string') { - var arr = new Array(data.length); - for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i); - data = arr; - } // make sure we can write to the file FS.chmod(node, mode | {{{ cDefs.S_IWUGO }}}); var stream = FS.open(node, {{{ cDefs.O_TRUNC | cDefs.O_CREAT | cDefs.O_WRONLY }}}); diff --git a/test/fs/test_insensitive_hang.c b/test/other/test_crash_icase.c similarity index 84% rename from test/fs/test_insensitive_hang.c rename to test/other/test_crash_icase.c index 37ceb6be7674a..dd7eb69b8ee84 100644 --- a/test/fs/test_insensitive_hang.c +++ b/test/other/test_crash_icase.c @@ -29,11 +29,11 @@ void loadScript() { } void scriptLoadFail() { - printf("failed to load second script\n"); + printf("failed to load data_files.js\n"); assert(false); } int main() { - emscripten_async_load_script("script.js", loadScript, scriptLoadFail); + emscripten_async_load_script("data_files.js", loadScript, scriptLoadFail); return 99; } diff --git a/test/fs/test_insensitive_overwrite.c b/test/other/test_overwrite_icase.c similarity index 100% rename from test/fs/test_insensitive_overwrite.c rename to test/other/test_overwrite_icase.c diff --git a/test/fs/test_insensitive_overwrite.js b/test/other/test_overwrite_icase.js similarity index 100% rename from test/fs/test_insensitive_overwrite.js rename to test/other/test_overwrite_icase.js diff --git a/test/fs/test_insensitive_overwrite.out b/test/other/test_overwrite_icase.out similarity index 100% rename from test/fs/test_insensitive_overwrite.out rename to test/other/test_overwrite_icase.out diff --git a/test/test_core.py b/test/test_core.py index 3d6fac3bd86d4..a55bf02c9b970 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -5957,21 +5957,6 @@ def test_fs_readv(self): def test_fs_writev(self): self.do_runf('fs/test_writev.c', 'success', cflags=['-sFORCE_FILESYSTEM']) - @no_modularize_instance('uses Module object directly') - def test_insensitive_hang(self): - create_file('file1.txt', 'one') - create_file('fILe1.txt', 'two') - # `--from-emcc` needed here otherwise the output defines `var Module =` which will shadow the - # global `Module`. - self.run_process([FILE_PACKAGER, 'test.data', '--preload', 'file1.txt', 'fILe1.txt', '--from-emcc', '--js-output=script.js']) - self.do_runf('fs/test_insensitive_hang.c', cflags=['-sFORCE_FILESYSTEM', '-sCASE_INSENSITIVE_FS']) - - def test_insensitive_overwrite(self): - self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', ['$FS']) - self.set_setting('CASE_INSENSITIVE_FS', ['1']) - self.add_pre_run(read_file(test_file('fs/test_insensitive_overwrite.js'))) - self.do_run_in_out_file_test('fs/test_insensitive_overwrite.c') - def test_fs_64bit(self): if self.get_setting('WASMFS'): self.set_setting('FORCE_FILESYSTEM') diff --git a/test/test_other.py b/test/test_other.py index 037eca335cf0f..92357b68e7e3c 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13815,6 +13815,20 @@ def test_recursive_cache_lock(self): def test_fs_icase(self): # c++20 for ends_with(). self.do_other_test('test_fs_icase.cpp', cflags=['-sCASE_INSENSITIVE_FS', '-std=c++20']) + self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', ['$FS']) + self.set_setting('CASE_INSENSITIVE_FS', 1) + self.add_pre_run(read_file(test_file('other/test_overwrite_icase.js'))) + self.do_run_in_out_file_test('other/test_overwrite_icase.c') + + @no_windows("Test requires case sensitive base FS") + @no_mac("Test requires case sensitive base FS") + def test_crash_icase(self): + create_file('file1.txt', 'one') + create_file('fILe1.txt', 'two') + # `--from-emcc` needed here otherwise the output defines `var Module =` which will shadow the + # global `Module`. + self.run_process([FILE_PACKAGER, 'test.data', '--preload', 'file1.txt', 'fILe1.txt', '--from-emcc', '--js-output=data_files.js']) + self.do_runf('other/test_crash_icase.c', cflags=['-sFORCE_FILESYSTEM', '-sCASE_INSENSITIVE_FS']) @crossplatform @with_all_fs From 399e6a9a9faa9a9bdd3cc16bb6838e0ce29425a7 Mon Sep 17 00:00:00 2001 From: walshal Date: Fri, 6 Mar 2026 10:05:30 -0800 Subject: [PATCH 10/12] Refactor overwrite test Refactored overwrite test in test_fs_icase to remove the stub .c file and the .out file, reducing it to a single .js file Signed-off-by: walshal --- test/other/test_overwrite_icase.c | 12 ------------ test/other/test_overwrite_icase.out | 3 --- test/test_other.py | 2 +- 3 files changed, 1 insertion(+), 16 deletions(-) delete mode 100644 test/other/test_overwrite_icase.c delete mode 100644 test/other/test_overwrite_icase.out diff --git a/test/other/test_overwrite_icase.c b/test/other/test_overwrite_icase.c deleted file mode 100644 index 57db8d9f47583..0000000000000 --- a/test/other/test_overwrite_icase.c +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright 2026 The Emscripten Authors. All rights reserved. - * Emscripten is available under two separate licenses, the MIT license and the - * University of Illinois/NCSA Open Source License. Both these licenses can be - * found in the LICENSE file. - */ - -int main() { - // Nothing to do here. Test is written in JS. See - // test/fs/test_insensitive_overwrite.js. - return 0; -} diff --git a/test/other/test_overwrite_icase.out b/test/other/test_overwrite_icase.out deleted file mode 100644 index 7b39a962c7dd9..0000000000000 --- a/test/other/test_overwrite_icase.out +++ /dev/null @@ -1,3 +0,0 @@ -file.txt: 102,111,111,50 -file.txt collison: undefined -errorCode: 20 diff --git a/test/test_other.py b/test/test_other.py index b82342a69401f..908f520cb31f5 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13818,7 +13818,7 @@ def test_fs_icase(self): self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', ['$FS']) self.set_setting('CASE_INSENSITIVE_FS', 1) self.add_pre_run(read_file(test_file('other/test_overwrite_icase.js'))) - self.do_run_in_out_file_test('other/test_overwrite_icase.c') + self.do_runf('hello_world.c', 'file.txt: 102,111,111,50\nfile.txt collison: undefined\nerrorCode: 20') @no_windows("Test requires case sensitive base FS") @no_mac("Test requires case sensitive base FS") From f22817a9838faba86a21e842b7e2e5704835d16c Mon Sep 17 00:00:00 2001 From: walshal Date: Mon, 9 Mar 2026 11:21:22 -0700 Subject: [PATCH 11/12] Test crossplatform of tests Split test_overwrite_icase back out into its own test temporarily, to more easily tell if it is crossplatform Mark both new tests as crossplatform Signed-off-by: walshal --- test/test_other.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/test_other.py b/test/test_other.py index 908f520cb31f5..11073f6516e77 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13812,16 +13812,21 @@ def test_recursive_cache_lock(self): self.assertContained('AssertionError: attempt to lock the cache while a parent process is holding the lock', err) @also_with_wasmfs + @crossplatform def test_fs_icase(self): # c++20 for ends_with(). self.do_other_test('test_fs_icase.cpp', cflags=['-sCASE_INSENSITIVE_FS', '-std=c++20']) + + @crossplatform + def test_overwrite_icase_temp(self): self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', ['$FS']) + self.set_setting('INCLUDE_FULL_LIBRARY', 1) self.set_setting('CASE_INSENSITIVE_FS', 1) self.add_pre_run(read_file(test_file('other/test_overwrite_icase.js'))) self.do_runf('hello_world.c', 'file.txt: 102,111,111,50\nfile.txt collison: undefined\nerrorCode: 20') - @no_windows("Test requires case sensitive base FS") - @no_mac("Test requires case sensitive base FS") + @crossplatform + @also_with_wasmfs def test_crash_icase(self): create_file('file1.txt', 'one') create_file('fILe1.txt', 'two') From 7a8f50ddb961d3631ce949be601fcaf7ce937ace Mon Sep 17 00:00:00 2001 From: walshal Date: Mon, 9 Mar 2026 16:09:01 -0700 Subject: [PATCH 12/12] Refactor tests Keep test_overwrite_icase outside of test_fs_icase for now since it fails with wasmfs Move test_crash_icase inside of test_fs_icase Keep crossplatform flags on icase tests - they pass as of now Signed-off-by: walshal --- test/test_other.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/test/test_other.py b/test/test_other.py index 11073f6516e77..11d55d1813b4c 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13816,25 +13816,21 @@ def test_recursive_cache_lock(self): def test_fs_icase(self): # c++20 for ends_with(). self.do_other_test('test_fs_icase.cpp', cflags=['-sCASE_INSENSITIVE_FS', '-std=c++20']) + create_file('file1.txt', 'one') + create_file('fILe1.txt', 'two') + # `--from-emcc` needed here otherwise the output defines `var Module =` which will shadow the + # global `Module`. + self.run_process([FILE_PACKAGER, 'test.data', '--preload', 'file1.txt', 'fILe1.txt', '--from-emcc', '--js-output=data_files.js']) + self.do_runf('other/test_crash_icase.c', cflags=['-sFORCE_FILESYSTEM', '-sCASE_INSENSITIVE_FS']) @crossplatform - def test_overwrite_icase_temp(self): + def test_overwrite_icase(self): self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', ['$FS']) self.set_setting('INCLUDE_FULL_LIBRARY', 1) self.set_setting('CASE_INSENSITIVE_FS', 1) self.add_pre_run(read_file(test_file('other/test_overwrite_icase.js'))) self.do_runf('hello_world.c', 'file.txt: 102,111,111,50\nfile.txt collison: undefined\nerrorCode: 20') - @crossplatform - @also_with_wasmfs - def test_crash_icase(self): - create_file('file1.txt', 'one') - create_file('fILe1.txt', 'two') - # `--from-emcc` needed here otherwise the output defines `var Module =` which will shadow the - # global `Module`. - self.run_process([FILE_PACKAGER, 'test.data', '--preload', 'file1.txt', 'fILe1.txt', '--from-emcc', '--js-output=data_files.js']) - self.do_runf('other/test_crash_icase.c', cflags=['-sFORCE_FILESYSTEM', '-sCASE_INSENSITIVE_FS']) - @crossplatform @with_all_fs def test_std_filesystem(self):