Skip to content

Commit 48e8a04

Browse files
authored
WasmFS JS API: Implement mount and unmount (#19825)
This PR implements FS.mount and FS.unmount. There were existing tests, so I just added some additional test cases to those files. Tests that now pass in WasmFS mode were also added to CI. There are some differences in the behavior of the WasmFS mount and the legacy API. For example, WasmFS mount will create a new directory to mount to if one does not already exist. Existing directories must be nonempty, since WasmFS will unlink the directory before creating a new directory with the specified backend. Currently, WasmFS does not support mounting IDBFS, WORKERFS, and PROXYFS, although those may be added in the future using a bridge to legacy backends (#18935)
1 parent 6f5b680 commit 48e8a04

19 files changed

+308
-14
lines changed

.circleci/config.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,13 +544,29 @@ jobs:
544544
wasmfs.test_readdir_unlink
545545
wasmfs.test_unistd_pipe
546546
wasmfs.test_fs_write
547+
wasmfs.test_fs_writev
548+
wasmfs.test_fs_writev_rawfs
549+
wasmfs.test_fs_writeFile
550+
wasmfs.test_fs_writeFile_rawfs
551+
wasmfs.test_fs_readv
552+
wasmfs.test_fs_write
553+
wasmfs.test_fs_readv_rawfs
554+
wasmfs.test_fs_nodefs_nofollow
555+
wasmfs.test_fs_nodefs_readdir
556+
wasmfs.test_fs_nodefs_home
557+
wasmfs.test_fs_nodefs_cloexec
558+
wasmfs.test_fs_nodefs_cloexec_rawfs
559+
wasmfs.test_fs_errorstack
560+
wasmfs.test_fs_errorstack_rawfs
561+
wasmfs.test_fs_emptyPath
547562
wasmfs.test_webidl
548563
wasmfs.test_dlfcn_self
549564
wasmfs.test_dlfcn_unique_sig
550565
wasmfs.test_dylink_basics
551566
wasmfs.test_exit_status
552567
wasmfs.test_minimal_runtime_memorygrowth
553568
wasmfs.test_mmap_anon*
569+
wasmfs.test_mount
554570
wasmfs.test_getcwd_with_non_ascii_name
555571
wasmfs.test_stat
556572
wasmfs.test_fstatat
@@ -559,6 +575,7 @@ jobs:
559575
wasmfs.test_fcntl_open
560576
wasmfs.test_fs_js_api
561577
wasmfs.test_fs_llseek
578+
wasmfs.test_fs_llseek_rawfs
562579
wasmfs.test_freetype"
563580
test-wasm2js1:
564581
environment:

emcc.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2339,6 +2339,8 @@ def phase_linker_setup(options, state, newargs):
23392339
# included, as the entire JS library can refer to things that require
23402340
# these exports.)
23412341
settings.REQUIRED_EXPORTS += [
2342+
'_wasmfs_mount',
2343+
'_wasmfs_unmount',
23422344
'_wasmfs_read_file',
23432345
'_wasmfs_write_file',
23442346
'_wasmfs_open',

src/library_fetchfs.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @license
3+
* Copyright 2023 The Emscripten Authors
4+
* SPDX-License-Identifier: MIT
5+
*/
6+
7+
mergeInto(LibraryManager.library, {
8+
$FETCHFS__deps: ['$stringToUTF8OnStack', 'wasmfs_create_fetch_backend'],
9+
$FETCHFS: {
10+
createBackend(opts) {
11+
return _wasmfs_create_fetch_backend(stringToUTF8OnStack(opts.base_url));
12+
}
13+
},
14+
});
15+
16+
if (!WASMFS) {
17+
error("using -lfetchfs.js requires using WasmFS (-sWASMFS)");
18+
}

src/library_icasefs.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* @license
3+
* Copyright 2023 The Emscripten Authors
4+
* SPDX-License-Identifier: MIT
5+
*/
6+
7+
mergeInto(LibraryManager.library, {
8+
$ICASEFS__deps: ['wasmfs_create_icase_backend'],
9+
$ICASEFS: {
10+
createBackend(opts) {
11+
if (typeof opts.backend === "undefined") {
12+
throw new Error("Underlying backend is not valid.");
13+
}
14+
var underlyingBackend = opts.backend.createBackend(opts);
15+
return _wasmfs_create_icase_backend(underlyingBackend);
16+
}
17+
},
18+
});
19+
20+
if (!WASMFS) {
21+
error("using -licasefs.js requires using WasmFS (-sWASMFS)");
22+
}

src/library_idbfs.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,3 +312,7 @@ mergeInto(LibraryManager.library, {
312312
}
313313
}
314314
});
315+
316+
if (WASMFS) {
317+
error("using -lidbfs is not currently supported in WasmFS.");
318+
}

src/library_jsfilefs.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @license
3+
* Copyright 2023 The Emscripten Authors
4+
* SPDX-License-Identifier: MIT
5+
*/
6+
7+
mergeInto(LibraryManager.library, {
8+
$JSFILEFS__deps: ['wasmfs_create_js_file_backend'],
9+
$JSFILEFS: {
10+
createBackend(opts) {
11+
return _wasmfs_create_js_file_backend();
12+
}
13+
},
14+
});
15+
16+
if (!WASMFS) {
17+
error("using -ljsfile.js requires using WasmFS (-sWASMFS)");
18+
}

src/library_nodefs.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@
55
*/
66

77
mergeInto(LibraryManager.library, {
8+
#if WASMFS
9+
$NODEFS__deps: ['$stringToUTF8OnStack', 'wasmfs_create_node_backend'],
10+
$NODEFS: {
11+
createBackend(opts) {
12+
return _wasmfs_create_node_backend(stringToUTF8OnStack(opts.root));
13+
}
14+
}
15+
#else
816
$NODEFS__deps: ['$FS', '$PATH', '$ERRNO_CODES', '$mmapAlloc'],
917
$NODEFS__postset: 'if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); }',
1018
$NODEFS: {
@@ -314,4 +322,5 @@ mergeInto(LibraryManager.library, {
314322
}
315323
}
316324
}
325+
#endif
317326
});

src/library_opfs.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @license
3+
* Copyright 2023 The Emscripten Authors
4+
* SPDX-License-Identifier: MIT
5+
*/
6+
7+
mergeInto(LibraryManager.library, {
8+
$OPFS__deps: ['wasmfs_create_opfs_backend'],
9+
$OPFS: {
10+
createBackend(opts) {
11+
return _wasmfs_create_opfs_backend();
12+
}
13+
},
14+
});
15+
16+
if (!WASMFS) {
17+
error("using -lopfs.js requires using WasmFS (-sWASMFS)");
18+
}

src/library_proxyfs.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,3 +218,7 @@ mergeInto(LibraryManager.library, {
218218
}
219219
}
220220
});
221+
222+
if (WASMFS) {
223+
error("using -lproxyfs is not currently supported in WasmFS.");
224+
}

src/library_wasmfs.js

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
*/
66

77
mergeInto(LibraryManager.library, {
8+
$MEMFS__deps: ['wasmfs_create_memory_backend'],
9+
$MEMFS: {
10+
createBackend(opts) {
11+
return _wasmfs_create_memory_backend();
12+
}
13+
},
814
$wasmFSPreloadedFiles: [],
915
$wasmFSPreloadedDirs: [],
1016
// We must note when preloading has been "flushed", that is, the time at which
@@ -18,6 +24,7 @@ FS.init();
1824
FS.createPreloadedFile = FS_createPreloadedFile;
1925
`,
2026
$FS__deps: [
27+
'$MEMFS',
2128
'$wasmFSPreloadedFiles',
2229
'$wasmFSPreloadedDirs',
2330
'$wasmFSPreloadingFlushed',
@@ -35,6 +42,21 @@ FS.createPreloadedFile = FS_createPreloadedFile;
3542
// up requiring all of our code
3643
// here.
3744
'$FS_modeStringToFlags',
45+
#if LibraryManager.has('library_icasefs.js')
46+
'$ICASEFS',
47+
#endif
48+
#if LibraryManager.has('library_nodefs.js')
49+
'$NODEFS',
50+
#endif
51+
#if LibraryManager.has('library_opfs.js')
52+
'$OPFS',
53+
#endif
54+
#if LibraryManager.has('library_jsfilefs.js')
55+
'$JSFILEFS',
56+
#endif
57+
#if LibraryManager.has('library_fetchfs.js')
58+
'$FETCHFS',
59+
#endif
3860
'malloc',
3961
'free',
4062
#endif
@@ -349,8 +371,20 @@ FS.createPreloadedFile = FS_createPreloadedFile;
349371
__wasmfs_readdir_finish(state);
350372
return entries;
351373
}),
352-
// TODO: mount
353-
// TODO: unmount
374+
mount: (type, opts, mountpoint) => {
375+
#if ASSERTIONS
376+
if (typeof type == 'string') {
377+
// The filesystem was not included, and instead we have an error
378+
// message stored in the variable.
379+
throw type;
380+
}
381+
#endif
382+
var backendPointer = type.createBackend(opts);
383+
return FS.handleError(withStackSave(() => __wasmfs_mount(stringToUTF8OnStack(mountpoint), backendPointer)));
384+
},
385+
unmount: (mountpoint) => (
386+
FS.handleError(withStackSave(() => __wasmfs_unmount(stringToUTF8OnStack(mountpoint))))
387+
),
354388
// TODO: lookup
355389
mknod(path, mode, dev) {
356390
return FS.handleError(withStackSave(() => {

0 commit comments

Comments
 (0)