Skip to content

[FS] Make fstatfs actually work #23381

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions src/library_fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
},
Expand Down
11 changes: 9 additions & 2 deletions src/library_noderawfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down
30 changes: 18 additions & 12 deletions src/library_syscall.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}});
Expand Down Expand Up @@ -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',
Expand Down
9 changes: 5 additions & 4 deletions test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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")
Expand Down
13 changes: 11 additions & 2 deletions test/unistd/fstatfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,20 @@
#include <stdio.h>
#include <sys/vfs.h>
#include <unistd.h>
#include <fcntl.h>

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;
}
Loading