diff --git a/src/library_fs.js b/src/library_fs.js index 3fe674378be0e..2bfeb673589cb 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -693,9 +693,18 @@ FS.staticInit(); return parent.node_ops.mknod(parent, name, mode, dev); }, statfs(path) { - + return FS.statfsNode(FS.lookupPath(path, {follow: true}).node); + }, + statfsStream(stream) { + // We keep a separate statfsStream function because noderawfs overrides + // it. In noderawfs, stream.node is sometimes null. Instead, we need to + // look at stream.path. + return FS.statfsNode(stream.node); + }, + statfsNode(node) { // NOTE: None of the defaults here are true. We're just returning safe and - // sane values. + // sane values. Currently nodefs and rawfs replace these defaults, + // other file systems leave them alone. var rtn = { bsize: 4096, frsize: 4096, @@ -709,9 +718,8 @@ FS.staticInit(); namelen: 255, }; - var parent = FS.lookupPath(path, {follow: true}).node; - if (parent?.node_ops.statfs) { - Object.assign(rtn, parent.node_ops.statfs(parent.mount.opts.root)); + if (node.node_ops.statfs) { + Object.assign(rtn, node.node_ops.statfs(node.mount.opts.root)); } return rtn; }, diff --git a/src/library_noderawfs.js b/src/library_noderawfs.js index 81ab16962a89c..89151b47c0a55 100644 --- a/src/library_noderawfs.js +++ b/src/library_noderawfs.js @@ -48,9 +48,10 @@ addToLibrary({ }, createStandardStreams() { // FIXME: tty is set to true to appease isatty(), the underlying ioctl syscalls still needs to be implemented, see issue #22264. - FS.createStream({ nfd: 0, position: 0, path: '', flags: 0, tty: true, seekable: false }, 0); + FS.createStream({ nfd: 0, position: 0, path: '/dev/stdin', flags: 0, tty: true, seekable: false }, 0); + var paths = [,'/dev/stdout', '/dev/stderr']; for (var i = 1; i < 3; i++) { - FS.createStream({ nfd: i, position: 0, path: '', flags: {{{ cDefs.O_TRUNC | cDefs.O_CREAT | cDefs.O_WRONLY }}}, tty: true, seekable: false }, i); + FS.createStream({ nfd: i, position: 0, path: paths[i], flags: {{{ cDefs.O_TRUNC | cDefs.O_CREAT | cDefs.O_WRONLY }}}, tty: true, seekable: false }, i); } }, // generic function for all node creation @@ -79,6 +80,12 @@ addToLibrary({ } return stat; }, + statfsStream(stream) { + return fs.statfsSync(stream.path); + }, + statfsNode(node) { + return fs.statfsSync(node.path); + }, chmod(path, mode, dontFollow) { mode &= {{{ cDefs.S_IALLUGO }}}; if (NODEFS.isWindows) { diff --git a/src/library_syscall.js b/src/library_syscall.js index 6acb166b457b8..41d2dfc4e1550 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -63,6 +63,18 @@ var SyscallsLibrary = { {{{ makeSetValue('buf', C_STRUCTS.stat.st_ino, 'stat.ino', 'i64') }}}; return 0; }, + writeStatFs(buf, stats) { + {{{ makeSetValue('buf', C_STRUCTS.statfs.f_bsize, 'stats.bsize', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statfs.f_frsize, 'stats.bsize', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statfs.f_blocks, 'stats.blocks', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statfs.f_bfree, 'stats.bfree', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statfs.f_bavail, 'stats.bavail', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statfs.f_files, 'stats.files', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statfs.f_ffree, 'stats.ffree', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statfs.f_fsid, 'stats.fsid', 'i32') }}}; + {{{ makeSetValue('buf', C_STRUCTS.statfs.f_flags, 'stats.flags', 'i32') }}}; // ST_NOSUID + {{{ makeSetValue('buf', C_STRUCTS.statfs.f_namelen, 'stats.namelen', 'i32') }}}; + }, doMsync(addr, stream, len, flags, offset) { if (!FS.isFile(stream.node.mode)) { throw new FS.ErrnoError({{{ cDefs.ENODEV }}}); @@ -801,23 +813,17 @@ var SyscallsLibrary = { #if ASSERTIONS assert(size === {{{ C_STRUCTS.statfs.__size__ }}}); #endif - var stats = FS.statfs(SYSCALLS.getStr(path)); - {{{ makeSetValue('buf', C_STRUCTS.statfs.f_bsize, 'stats.bsize', 'i32') }}}; - {{{ makeSetValue('buf', C_STRUCTS.statfs.f_frsize, 'stats.bsize', 'i32') }}}; - {{{ makeSetValue('buf', C_STRUCTS.statfs.f_blocks, 'stats.blocks', 'i32') }}}; - {{{ makeSetValue('buf', C_STRUCTS.statfs.f_bfree, 'stats.bfree', 'i32') }}}; - {{{ makeSetValue('buf', C_STRUCTS.statfs.f_bavail, 'stats.bavail', 'i32') }}}; - {{{ makeSetValue('buf', C_STRUCTS.statfs.f_files, 'stats.files', 'i32') }}}; - {{{ makeSetValue('buf', C_STRUCTS.statfs.f_ffree, 'stats.ffree', 'i32') }}}; - {{{ makeSetValue('buf', C_STRUCTS.statfs.f_fsid, 'stats.fsid', 'i32') }}}; - {{{ makeSetValue('buf', C_STRUCTS.statfs.f_flags, 'stats.flags', 'i32') }}}; // ST_NOSUID - {{{ makeSetValue('buf', C_STRUCTS.statfs.f_namelen, 'stats.namelen', 'i32') }}}; + SYSCALLS.writeStatFs(buf, FS.statfs(SYSCALLS.getStr(path))); return 0; }, __syscall_fstatfs64__deps: ['__syscall_statfs64'], __syscall_fstatfs64: (fd, size, buf) => { +#if ASSERTIONS + assert(size === {{{ C_STRUCTS.statfs.__size__ }}}); +#endif var stream = SYSCALLS.getStreamFromFD(fd); - return ___syscall_statfs64(0, size, buf); + SYSCALLS.writeStatFs(buf, FS.statfsStream(stream)); + return 0; }, __syscall_fadvise64__nothrow: true, __syscall_fadvise64__proxy: 'none', diff --git a/test/test_other.py b/test/test_other.py index 6e8275a1d49c3..4eaa556bbeac1 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -36,7 +36,7 @@ from common import create_file, parameterized, NON_ZERO, node_pthreads, TEST_ROOT, test_file from common import compiler_for, EMBUILDER, requires_v8, requires_node, requires_wasm64, requires_node_canary from common import requires_wasm_eh, crossplatform, with_all_eh_sjlj, with_all_sjlj -from common import also_with_standalone_wasm, also_with_wasm2js, also_with_noderawfs, also_with_wasmfs +from common import also_with_standalone_wasm, also_with_wasm2js, also_with_noderawfs, also_with_wasmfs, with_all_fs from common import also_with_minimal_runtime, also_with_wasm_bigint, also_with_wasm64, flaky from common import EMTEST_BUILD_VERBOSE, PYTHON, WEBIDL_BINDER from common import requires_network, parameterize @@ -13741,10 +13741,11 @@ def test_unistd_login(self): def test_unistd_sleep(self): self.do_run_in_out_file_test('unistd/sleep.c') - @also_with_wasmfs + @crossplatform + @with_all_fs def test_unistd_fstatfs(self): - if not self.get_setting('WASMFS'): - self.skipTest("fstatfs is broken in js fs, will be fixed in PR #23381") + if '-DNODERAWFS' in self.emcc_args and WINDOWS: + self.skipTest('Cannot look up /dev/stdout on windows') self.do_run_in_out_file_test('unistd/fstatfs.c') @no_windows("test is Linux-specific") diff --git a/test/unistd/fstatfs.c b/test/unistd/fstatfs.c index 6d9cf08d2413b..be6c602d3e692 100644 --- a/test/unistd/fstatfs.c +++ b/test/unistd/fstatfs.c @@ -2,11 +2,20 @@ #include #include #include +#include int main() { struct statfs buf; - int rtn = fstatfs(STDOUT_FILENO, &buf); - assert(rtn == 0); + + int rtn; + assert(fstatfs(STDOUT_FILENO, &buf) == 0); + printf("f_type: %ld\n", buf.f_type); + + int f = open("file", O_RDWR | O_CREAT); + assert(fstatfs(f, &buf) == 0); + printf("f_type: %ld\n", buf.f_type); + + assert(statfs("file", &buf) == 0); printf("f_type: %ld\n", buf.f_type); return 0; }