diff --git a/src/library_syscall.js b/src/library_syscall.js index fde42e8a48428..3e857b344d141 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -695,9 +695,9 @@ var SyscallsLibrary = { var pos = 0; var off = FS.llseek(stream, 0, {{{ cDefs.SEEK_CUR }}}); - var idx = Math.floor(off / struct_size); - - while (idx < stream.getdents.length && pos + struct_size <= count) { + var startIdx = Math.floor(off / struct_size); + var endIdx = Math.min(stream.getdents.length, startIdx + Math.floor(count/struct_size)) + for (var idx = startIdx; idx < endIdx; idx++) { var id; var type; var name = stream.getdents[idx]; @@ -711,7 +711,17 @@ var SyscallsLibrary = { type = 4; // DT_DIR } else { - var child = FS.lookupNode(stream.node, name); + var child; + try { + child = FS.lookupNode(stream.node, name); + } catch (e) { + // If the entry is not a directory, file, or symlink, nodefs + // lookupNode will raise EINVAL. Skip these and continue. + if (e?.errno === {{{ cDefs.EINVAL }}}) { + continue; + } + throw e; + } id = child.id; type = FS.isChrdev(child.mode) ? 2 : // DT_CHR, character device. FS.isDir(child.mode) ? 4 : // DT_DIR, directory. @@ -727,7 +737,6 @@ var SyscallsLibrary = { {{{ makeSetValue('dirp + pos', C_STRUCTS.dirent.d_type, 'type', 'i8') }}}; stringToUTF8(name, dirp + pos + {{{ C_STRUCTS.dirent.d_name }}}, 256); pos += struct_size; - idx += 1; } FS.llseek(stream, idx * struct_size, {{{ cDefs.SEEK_SET }}}); return pos; diff --git a/test/fs/test_nodefs_readdir.out b/test/fs/test_nodefs_readdir.out new file mode 100644 index 0000000000000..293d117dc7251 --- /dev/null +++ b/test/fs/test_nodefs_readdir.out @@ -0,0 +1,13 @@ +listing contents of dir=/ +. +.. +tmp +home +dev +proc +listing contents of dir=/working +existing +stdout +test_nodefs_readdir.js +test_nodefs_readdir.wasm +success diff --git a/test/fs/test_nodefs_readdir.wasm2js.out b/test/fs/test_nodefs_readdir.wasm2js.out new file mode 100644 index 0000000000000..cc2268c8bcb8a --- /dev/null +++ b/test/fs/test_nodefs_readdir.wasm2js.out @@ -0,0 +1,12 @@ +listing contents of dir=/ +. +.. +tmp +home +dev +proc +listing contents of dir=/working +existing +stdout +test_nodefs_readdir.js +success diff --git a/test/fs/test_nodefs_readdir.wasmfs.out b/test/fs/test_nodefs_readdir.wasmfs.out new file mode 100644 index 0000000000000..bf8f2ad9fa60a --- /dev/null +++ b/test/fs/test_nodefs_readdir.wasmfs.out @@ -0,0 +1,14 @@ +listing contents of dir=/ +. +.. +dev +tmp +listing contents of dir=/working +. +.. +existing +named_pipe +stdout +test_nodefs_readdir.js +test_nodefs_readdir.wasm +success diff --git a/test/test_core.py b/test/test_core.py index f3a2297e73194..82db1dbd35ff9 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -5779,14 +5779,24 @@ def test_fs_nodefs_nofollow(self): self.emcc_args += ['-lnodefs.js'] self.do_runf('fs/test_nodefs_nofollow.c', 'success') + @crossplatform @requires_node def test_fs_nodefs_readdir(self): # externally setup an existing folder structure: existing/a if self.get_setting('WASMFS'): self.set_setting('FORCE_FILESYSTEM') + if not WINDOWS: + # Add an entry that isn't a directory, file, or link to test that we handle + # it correctly. + os.mkfifo('named_pipe') os.makedirs('existing/a') self.emcc_args += ['-lnodefs.js'] - self.do_runf('fs/test_nodefs_readdir.c', 'success') + suffix = '' + if self.get_setting('WASMFS'): + suffix = '.wasmfs' + elif self.is_wasm2js(): + suffix = ".wasm2js" + self.do_run_in_out_file_test('fs/test_nodefs_readdir.c', out_suffix=suffix) @requires_node @crossplatform