Skip to content

Commit 4c2d596

Browse files
committed
[WasmFS] Fix absolute path access under NODERAWFS
Resolves: #24830. Resolves: #24836.
1 parent de5d6f0 commit 4c2d596

File tree

8 files changed

+74
-19
lines changed

8 files changed

+74
-19
lines changed

src/lib/libwasmfs_node.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ addToLibrary({
206206
return wasmfsTry(() => {
207207
// TODO: Cache open file descriptors to guarantee that opened files will
208208
// still exist when we try to access them.
209-
let nread = fs.readSync(fd, new Int8Array(HEAPU8.buffer, buf_p, len), 0, len, pos);
209+
let nread = fs.readSync(fd, HEAPU8.subarray(buf_p, buf_p + len), 0, len, pos);
210210
{{{ makeSetValue('nread_p', 0, 'nread', 'i32') }}};
211211
// implicitly return 0
212212
});
@@ -217,7 +217,7 @@ addToLibrary({
217217
return wasmfsTry(() => {
218218
// TODO: Cache open file descriptors to guarantee that opened files will
219219
// still exist when we try to access them.
220-
let nwritten = fs.writeSync(fd, new Int8Array(HEAPU8.buffer, buf_p, len), 0, len, pos);
220+
let nwritten = fs.writeSync(fd, HEAPU8.subarray(buf_p, buf_p + len), 0, len, pos);
221221
{{{ makeSetValue('nwritten_p', 0, 'nwritten', 'i32') }}};
222222
// implicitly return 0
223223
});

system/include/emscripten/wasmfs.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ backend_t wasmfs_create_memory_backend(void);
7777
//
7878
backend_t wasmfs_create_fetch_backend(const char* _Nonnull base_url, uint32_t chunk_size);
7979

80-
backend_t wasmfs_create_node_backend(const char* _Nonnull root);
80+
backend_t wasmfs_create_node_backend(const char* _Nonnull mount_path);
8181

8282
// Note: this cannot be called on the browser main thread because it might
8383
// deadlock while waiting for the OPFS dedicated worker thread to be spawned.
@@ -111,6 +111,11 @@ void wasmfs_flush(void);
111111
// default backend is used.
112112
backend_t wasmfs_create_root_dir(void);
113113

114+
// A hook users can do to create the working directory. Overriding this allows
115+
// the user to set a particular backend as the CWD. If this is not set then the
116+
// result of wasmfs_create_root_dir() is used.
117+
backend_t wasmfs_create_working_dir(void);
118+
114119
// A hook users can do to run code during WasmFS startup. This hook happens
115120
// before file preloading, so user code could create backends and mount them,
116121
// which would then affect in which backend the preloaded files are loaded (the

system/lib/wasmfs/backends/node_backend.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,9 @@ class NodeDirectory : public Directory {
191191
if (_wasmfs_node_get_mode(childPath.c_str(), &mode)) {
192192
return nullptr;
193193
}
194-
if (S_ISREG(mode)) {
194+
// Allow reading from character device files (e.g. `/dev/random`,
195+
// `/dev/urandom`)
196+
if (S_ISREG(mode) || S_ISCHR(mode)) {
195197
return std::make_shared<NodeFile>(mode, getBackend(), childPath);
196198
} else if (S_ISDIR(mode)) {
197199
return std::make_shared<NodeDirectory>(mode, getBackend(), childPath);
@@ -300,8 +302,8 @@ class NodeBackend : public Backend {
300302

301303
extern "C" {
302304

303-
backend_t wasmfs_create_node_backend(const char* root) {
304-
return wasmFS.addBackend(std::make_unique<NodeBackend>(root));
305+
backend_t wasmfs_create_node_backend(const char* mount_path) {
306+
return wasmFS.addBackend(std::make_unique<NodeBackend>(mount_path));
305307
}
306308

307309
void EMSCRIPTEN_KEEPALIVE _wasmfs_node_record_dirent(

system/lib/wasmfs/backends/noderawfs_root.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55

66
#include "emscripten/wasmfs.h"
77

8-
backend_t wasmfs_create_root_dir(void) {
8+
backend_t wasmfs_create_root_dir() {
9+
return wasmfs_create_node_backend("");
10+
}
11+
12+
backend_t wasmfs_create_working_dir() {
913
return wasmfs_create_node_backend(".");
1014
}

system/lib/wasmfs/wasmfs.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ __attribute__((init_priority(100))) WasmFS wasmFS;
3737
__attribute__((weak)) extern "C" void wasmfs_before_preload(void) {}
3838

3939
// Set up global data structures and preload files.
40-
WasmFS::WasmFS() : rootDirectory(initRootDirectory()), cwd(rootDirectory) {
40+
WasmFS::WasmFS() : rootDirectory(initRootDirectory()), cwd(initCWD()) {
4141
wasmfs_before_preload();
4242
preloadFiles();
4343
}
@@ -87,8 +87,8 @@ WasmFS::~WasmFS() {
8787
rootDirectory->locked().setParent(nullptr);
8888
}
8989

90-
// Special backends that want to install themselves as the root use this hook.
91-
// Otherwise, we use the default backends.
90+
// Hooks for backends that want to install themselves as the root or CWD.
91+
// Otherwise, we use the default memory backends.
9292
__attribute__((weak)) extern "C" backend_t wasmfs_create_root_dir(void) {
9393
#ifdef WASMFS_CASE_INSENSITIVE
9494
return createIgnoreCaseBackend([]() { return createMemoryBackend(); });
@@ -97,6 +97,8 @@ __attribute__((weak)) extern "C" backend_t wasmfs_create_root_dir(void) {
9797
#endif
9898
}
9999

100+
__attribute__((weak)) extern "C" backend_t wasmfs_create_working_dir(void);
101+
100102
std::shared_ptr<Directory> WasmFS::initRootDirectory() {
101103
auto rootBackend = wasmfs_create_root_dir();
102104
auto rootDirectory =
@@ -126,6 +128,21 @@ std::shared_ptr<Directory> WasmFS::initRootDirectory() {
126128
return rootDirectory;
127129
}
128130

131+
std::shared_ptr<Directory> WasmFS::initCWD() {
132+
if (wasmfs_create_working_dir == nullptr) {
133+
return rootDirectory;
134+
}
135+
136+
auto cwdBackend = wasmfs_create_working_dir();
137+
auto cwd = cwdBackend->createDirectory(S_IRUGO | S_IXUGO | S_IWUGO);
138+
auto lockedCwd = cwd->locked();
139+
140+
// The current working directory is its own parent.
141+
lockedCwd.setParent(cwd);
142+
143+
return cwd;
144+
}
145+
129146
// Initialize files specified by the --preload-file option.
130147
// Set up directories and files in wasmFS$preloadedDirs and
131148
// wasmFS$preloadedFiles from JS. This function will be called before any file

system/lib/wasmfs/wasmfs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ class WasmFS {
3232
// dev/stderr. Refers to the same std streams in the open file table.
3333
std::shared_ptr<Directory> initRootDirectory();
3434

35+
// Private method to initialize CWD once.
36+
std::shared_ptr<Directory> initCWD();
37+
3538
// Initialize files specified by --preload-file option.
3639
void preloadFiles();
3740

test/fs/test_fs_dev_random.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ int main() {
1313
int nread;
1414

1515
fp = fopen("/dev/random", "r");
16-
nread = fread(&data, 1, byte_count, fp);
16+
assert(fp != NULL);
17+
nread = fread(data, 1, byte_count, fp);
1718
assert(nread == byte_count);
1819
fclose(fp);
1920

2021
fp = fopen("/dev/urandom", "r");
21-
nread = fread(&data, 1, byte_count, fp);
22+
assert(fp != NULL);
23+
nread = fread(data, 1, byte_count, fp);
2224
assert(nread == byte_count);
2325
fclose(fp);
2426

test/test_other.py

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9255,16 +9255,43 @@ def test_noderawfs_disables_embedding(self):
92559255
self.assert_fail(base + ['--preload-file', 'somefile'], expected)
92569256
self.assert_fail(base + ['--embed-file', 'somefile'], expected)
92579257

9258+
@crossplatform
9259+
@also_with_wasmfs
92589260
def test_noderawfs_access_abspath(self):
92599261
create_file('foo', 'bar')
92609262
create_file('access.c', r'''
9263+
#include <stdio.h>
9264+
#include <assert.h>
92619265
#include <unistd.h>
92629266
int main(int argc, char** argv) {
9263-
return access(argv[1], F_OK);
9267+
printf("testing access to %s\n", argv[1]);
9268+
int rtn = access(argv[1], F_OK);
9269+
assert(rtn == 0);
9270+
return 0;
92649271
}
92659272
''')
92669273
self.do_runf('access.c', cflags=['-sNODERAWFS'], args=[os.path.abspath('foo')])
92679274

9275+
@crossplatform
9276+
@also_with_wasmfs
9277+
def test_noderawfs_open_abspath(self):
9278+
create_file('foo', 'bar')
9279+
create_file('open.c', r'''
9280+
#include <stdio.h>
9281+
#include <fcntl.h>
9282+
#include <assert.h>
9283+
#include <unistd.h>
9284+
int main(int argc, char** argv) {
9285+
printf("testing open to %s\n", argv[1]);
9286+
int fd = open(argv[1], O_RDONLY, 0644);
9287+
assert(fd >= 0);
9288+
int rtn = close(fd);
9289+
assert(rtn == 0);
9290+
return 0;
9291+
}
9292+
''')
9293+
self.do_runf('open.c', cflags=['-sNODERAWFS'], args=[os.path.abspath('foo')])
9294+
92689295
def test_noderawfs_readfile_prerun(self):
92699296
create_file('foo', 'bar')
92709297
self.add_pre_run("console.log(FS.readFile('foo', { encoding: 'utf8' }));")
@@ -13210,11 +13237,10 @@ def test_unistd_chown(self):
1321013237
self.set_setting('WASMFS')
1321113238
self.do_run_in_out_file_test('wasmfs/wasmfs_chown.c')
1321213239

13213-
@wasmfs_all_backends
1321413240
def test_wasmfs_getdents(self):
1321513241
# Run only in WASMFS for now.
1321613242
self.set_setting('FORCE_FILESYSTEM')
13217-
self.do_run_in_out_file_test('wasmfs/wasmfs_getdents.c')
13243+
self.do_run_in_out_file_test('wasmfs/wasmfs_getdents.c', cflags=['-sWASMFS'])
1321813244

1321913245
def test_wasmfs_jsfile(self):
1322013246
self.set_setting('WASMFS')
@@ -13801,15 +13827,11 @@ def test_fs_icase(self):
1380113827
@crossplatform
1380213828
@with_all_fs
1380313829
def test_std_filesystem(self):
13804-
if self.get_setting('NODERAWFS') and self.get_setting('WASMFS'):
13805-
self.skipTest('https://github.com/emscripten-core/emscripten/issues/24830')
1380613830
self.do_other_test('test_std_filesystem.cpp')
1380713831

1380813832
@crossplatform
1380913833
@with_all_fs
1381013834
def test_std_filesystem_tempdir(self):
13811-
if self.get_setting('NODERAWFS') and self.get_setting('WASMFS'):
13812-
self.skipTest('https://github.com/emscripten-core/emscripten/issues/24830')
1381313835
self.do_other_test('test_std_filesystem_tempdir.cpp', cflags=['-g'])
1381413836

1381513837
def test_strict_js_closure(self):

0 commit comments

Comments
 (0)